二分查找模板

97 阅读1分钟

二分查找很容易出错,判断条件怎么定?如何确定是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的下标

具体可以参考www.bilibili.com/video/BV1d5…