二分答案
二分答案是一种高效的算法技巧,通常用于解决最优化问题,尤其是当问题具有单调性时。它的核心思想是通过二分查找来快速缩小答案的范围,从而找到最优解。
适用场景
二分答案常用于以下类型的问题:
- 最大值最小化或最小值最大化问题。
- 问题具有单调性,即当答案增大或减小时,问题的可行性会呈现单调变化。
- 直接求解问题较为复杂,但可以通过给定答案快速验证其可行性。
算法步骤
- 确定搜索范围:根据问题的性质,确定答案的可能范围
[left, right]
。 - 二分查找:
- 计算中间值
mid = left + (right - left) / 2
。 - 检查
mid
是否满足条件(即验证可行性)。 - 如果满足条件,尝试寻找更优的解(缩小右边界
right = mid
)。 - 如果不满足条件,调整左边界
left = mid + 1
。
- 计算中间值
- 终止条件:当
left
和right
相遇时,找到最优解。
代码模板
以下是二分答案的通用代码模板(以 C++ 为例):
int binarySearchAnswer(int left, int right) { while (left < right) { int mid = left + (right - left) / 2; if (check(mid)) { // 检查 mid 是否满足条件 right = mid; // 满足条件,尝试更小的值 } else { left = mid + 1; // 不满足条件,尝试更大的值 } } return left; // 返回最优解 } bool check(int mid) { // 根据问题实现具体的检查逻辑 // 返回 true 或 false }
示例问题
问题:分割数组的最大值
给定一个数组 nums
和一个整数 k
,将数组分成 k
个连续子数组,使得每个子数组的和的最大值最小化。
解题思路
- 确定搜索范围:
- 最小可能值:数组中的最大值(每个子数组至少包含一个元素)。
- 最大可能值:数组的总和(整个数组作为一个子数组)。
- 二分查找:
- 对于每个
mid
,检查是否可以将数组分成k
个子数组,且每个子数组的和不超过mid
。
- 对于每个
- 验证函数:
- 遍历数组,累加元素,当累加和超过
mid
时,分割一个新的子数组。 - 如果分割的子数组数量不超过
k
,则mid
可行。
- 遍历数组,累加元素,当累加和超过
代码实现
int splitArray(vector<int>& nums, int k) { int left = *max_element(nums.begin(), nums.end()); int right = accumulate(nums.begin(), nums.end(), 0); while (left < right) { int mid = left + (right - left) / 2; if (canSplit(nums, k, mid)) { right = mid; } else { left = mid + 1; } } return left; } bool canSplit(vector<int>& nums, int k, int maxSum) { int sum = 0, count = 1; for (int num : nums) { sum += num; if (sum > maxSum) { sum = num; count++; if (count > k) return false; } } return true; }
总结
二分答案的关键在于:
- 确定答案的搜索范围。
- 实现一个高效的验证函数
check(mid)
。 - 通过二分查找快速缩小范围,找到最优解。
通过练习经典问题(如分割数组、最小化最大值等),可以更好地掌握这一技巧。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律