引言
二分查找,又称折半查找。该算法每次将搜索范围缩小一半。
二分算法主要分为二分查找和二分答案两类。
以在升序数组中查找一个数为例:每次考察当前部分的中间元素,若中间元素等于目标值则结束;若小于目标值,则在右侧查找;若大于目标值,则在左侧查找。
二分法的使用条件
二分法适用于解决具有'二段性'(单调性)的问题,通常表现为求解满足某一条件的最大值或最小值。
上下界确定:可通过上下界的折半来优化查找。 二段性:对某一范围内的数据,存在一个临界点,使得临界点某一侧的所有数据都满足某一性质,另一侧都不满足。二段性包括单调性(区间内有序),也体现在非单调性上(局部有序),例如寻找峰值或旋转排序数组。
二分的前提条件
- 答案在一个区间内(一般区间很大,暴力会超时)。
- 直接搜索困难,但容易判断一个答案是否可行。
- 该区间对题目具有单调性,即区间中的值越大或越小,题目中的某个量对应增加或减少。
- 若有多个答案满足题意,则这些答案具有连续性:若答案 x 满足,则答案范围内小于 x 或大于 x 的答案均满足。
模板
1. 朴素版
while (l <= r) {
int mid = (r - l) / 2 + l; // 防止溢出,等价于 (r - l + 1) / 2 + l
if (...) l = mid + 1;
else if (...) r = mid - 1;
else return ...;
}
2. 求大于等于目标的最小值(查找区间左端点)
while (l < r) { // 区间不为空
int mid = ((r - l) >> 1) + l;
if (...) l = mid + 1;
else r = mid;
}
3. 求小于等于目标的最大值(查找区间右端点)
while (l < r) {
// 当 l,r 相邻时,会 l=mid,<r,死循环,模板 1 不影响,因为 l=mid+1=r
int mid = ((r - l + 1) >> 1) + l;
if (...) l = mid;
else r = mid - 1;
}
4. 优化版模板
统一处理左右边界逻辑,无需单独考虑 Mid+1 问题。


