二分分为两大块:
- 整数二分(蛋疼)
- 浮点数二分
以后用q代替一个有序数组(有单调性的数组一定可以二分)
整数二分
整数二分的本质是边界。
思想:
大体思路:定义一种性质check,把q分成两部分(两部分没有交点),左半边不满足性质,右半边满足性质,可以求出性质的边界,两种情况。
第一种:要求的是左半边的边界
第一步:定义中间点mid=(l+r+1)/2,判断它满不满足cheak
- 满足。边界在[l,mid−1],r=mid−1。
- 不满足。边界在[mid,r],l=mid;
第二步:重复第一步,直到l=r,ql(或qr)就是答案。
第二种:要求的是右半边的边界
第一步:定义中间点mid=(l+r)/2,判断它满不满足cheak
- 满足。边界在[l,mid],r=mid。
- 不满足。边界在[mid+1,r],l=mid+1;
第二步与第一种情况一样。
一个问题:为什么第一种情况的mid还要+1。
答:如果没有+1,当l=r−1的时候,如果check成功了,l=mid=l,就陷入死循环了。
模版:
bool check(int mid){
按情况而定;
}
情况一:
int bsearch(int l, int r){
while (l < r){
int mid = l + r + 1 >> 1;
if (cheak(mid)) r = mid - 1;
else l = mid;
}
return l;
}
情况二:
int bsearch(int l, int r){
while (l < r){
int mid = l + r >> 1;
if (cheak(mid)) r = mid;
else l = mid + 1;
}
}
浮点数二分
本质也是边界(没整数二分那么蛋疼)
思路:
大体思路:跟整数二分差不多,只是浮点数没有整除,所以每次都能严格分成两半
第一步:定义中间点mid=(l+r)/2,判断他满不满足check
- 满足。答案在[l,mid]中,r=mid。
- 不满足。答案在[mid,r]中,l=mid。
第二步:重复第一步,直到l和r相差非常小,精度足够了的时候,可以输出l或r。
模版:
先定义check
int bsearch(double l, double r){
while (r - l < 精度){
double mid = l + r >> 1;
if (check(mid)) l = mid;
else r = mid;
}
return l;
}