二分的关键在于如何正确的划分区间,那么问题就来了:
一般都是将区间划分成两个部分,如[l, mid], [mid + 1, r]
or [l, mid - 1], [mid, r]
两者区别在于mid到底放在哪一个集合里面
我们就用二分经典的问题lower_bound
来理清代码思路。
首先这里的lower_bound
的定义是: 第一个 >= target的值的索引
第一种写法
// [0, n) 寻找 target lower_bound
// [idx, n) >= target
int lower_bound(int * arr, int n, int target) {
if (arr[n-1] < target) return -1;
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r >> 1;
if (arr[mid] >= target)
r = mid; // 请仔细理解这里 *
else
l = mid + 1;
}
//如果 target < arr[0],则为 0
//如果 arr[n-1] < target, 则为-1 或者 n
// * 如果target < arr[mid],则 target 在左边,所以选择左区间,同时arr[mid]本身也可能是答案,则 r = mid;
//同时如果不好想,就考虑 target = arr[mid]的情况,这里找下边界,答案肯定在[l, mid]中
// 这里是关键,试想如果找上边界,则答案应该在[mid, r]中找,请仔细体会,
// arr[mid] < target 和 arr[mid] > target 两种情况下写法都不变,请仔细体会。
}