概念要求
二分用来找边界值,例如查找最后一个小于x的数,
取中间值,每次判断是否满足条件(例如小于),如果满足就接着找,变化左边界与有边界
要求: 数组单调 这个单调并不是说数值上单调,而是满足某种性质,这种性质左边的没有,右边的有,利用这个性质就可以找到其分界点
实现
//找到最后一个小于等于x的数
int l = 0, r = len;
while(l <= r)
{
int mid = l + r + 1 >> 1;
if(a[mid] < x) l = mid;
else r = mid - 1;
}
//第一个大于等于x的数
while(l <= r)
{
int mid = l + r >> 1;
if(a[mid] >= x) r = mid;
else l = mid + 1;
}
while(l < r){
int mid = l + r >> 1;
if(check(q[mid])) r = mid;
else l = mid + 1;
}
while(l < r){
int mid = l + r + 1 >> 1;
if(check(q[mid])) l = mid;
else r = mid - 1;
}
实际上是,当q[mid]
满足check的时候,mid本身包含在满足性质的一边,让 r=mid
或者l=mid
其实是默认要找的边界是满足性质的,所以下面两个模板是找
- check检查右边性质:满足性质的第一个
- check检查左边性质:满足性质的最后一个
实现上要注意几点:
- 怎么写其实是由逻辑决定的 要找到的数如果是包含在条件里的,那么mid就包含在下一个要找的区间里
- 为了防止死循环所以在<的条件下要再加上1
设想,如果3个数,例如1 2 3
找大于2的数,第一次找2,发现不对,再找,
l+r >> 1
,结果还是2,进入死循环(这是由于除法的向下取整) - 同时,while条件和 if 条件最好不要都有等于,可能会死循环