二分查找很容易出错,判断条件怎么定?如何确定是mid + 1 还是mid - 1?找到了一个模板用于解决二分查找边界的问题。
模板:
l = -1, r = N
while(l + 1 != r){
mid = l + r >> 1;
if(check()) l = mid;
else r = mid;
}
return l or r(视情况而定)
在这个模板中,我们把整个数组划分成两块。check函数用于判断mid在不在左边的那一块。这个算法最终可以找到这两块的边界l和r。
举个例子,数组1 2 2 3 3 4,我们需要找到3的左边界和右边界
找左边界的时候,所找的是第一个等于3的数。所以我们可以把数组划分为下<3和>=3的两个部分,也就是
1 2 2 | 3 3 4
此时代码为:
l = -1, r = N;
while(l + 1 != r){
mid = l + r >> 1;
if(q[l] < 3) l = mid;
else r = mid;
}
return r;
找右边界的时候,所找的是最后一个等于3的数,所以我们可以把数组划分为<=3和>3的两个部分,也就是
1 2 2 3 3 | 4
此时代码为
l = -1, r = N;
while(l + 1 != r){
mid = l + r >> 1;
if(q[l] <= 3) l = mid;
else r = mid;
}
return l;
在stl中有专门的库函数用于解决数的范围的问题:
Eg: 1 2 3 5 5 5 8 9
找到连续分布的数的下边界的下标:
std::lower_bound()
这里找到的是第一个5的下标
找到连续分布的数的上边界的下标 + 1:(后面那一个,这里相当于是左闭右开区间)
std::upper_bound()
这里找到的是8的下标