思想:二分就是找到序列满足的性质,该性质使得序列的一边满足,另一边不满足,这个边界就是要求的答案
原则:单调序列可以二分,但是二分不一定需要单调
二分 分为整数二分和实数二分,其中整数二分更需要注意边界问题
二分查找的最坏情况是 O(logn)
模板:
1.构造check函数 (比如 >= x)
2.取mid = left + right / 2 判断是否满足某种性质
//1.若答案在左边界
mid = l + r + 1 >> 1
if(check(mid){//mid满足左区间的性质
l = mid;
mid = l + r + 1 >> 1
else{
r = mid - 1;//因为mid是不满足的,所以是mid - 1
mid = l + r + 1 >> 1
}
//2.若答案在右边界
mid = l + r >> 1
if(check(mid)){//mid满足右区间的性质
r = mid;
mid = l + r >> 1
}
else{
l = mid + 1;
mid = l + r >> 1;
}
判断mid是否需要加1只需要判断 l = mid 还是 r = mid
如果 l = mid,若 l = r - 1, mid = l + r >> 1
mid = l + l + 1 / 2 , 下取整得到 mid = l
那么下一次的判断区间就还是[l, r],就会陷入死循环中
然而对于浮点数二分来说,就没有这么复杂的边界问题,根据保留小数位数再精确2位即可
若题中要保留四位小数
while(r - l > 1e-6){ 一定要注意1e-6这个条件啊!
mid = l + r >> 1
}
总结:
具体题目中不需要考虑这么多,答案究竟在左边界还是在右边界
只需要
1.总结题中规律性质,写好check函数
2.判断 ture 的情况 l = mid 还是 r = mid
3.+1 or not
4.最后不要忘记特殊情况的判断,可能找不到要的结果、无解的情况