最近做题做二分老是卡,于是总结一下:
本人二分做题不多,只遇到过三种情况,如有错误请大佬指正:
1、递增序(即若(0,x)位置满足条件,(x + 1, n)均不满足),找最后一个满足条件的位置,如找满足某条件的最大长度。
2、递减序(即若(x + 1, n)位置满足条件,(0, x)均不满足)找第一个满足条件的位置,如找满足某条件的最小值。
3、局部满足,找任意一个递增和递减的交界点。
下面假设bool check(int n)当位置满足条件时返回true,否则返回false.
1、递增,找最后一个位置:(这种打法不需要额外确认边界条件,用ans即可判断)
目前找到的最朴实的代码,虽然每次搜索要比单边界多走一次,但是易于掌握,已储备为个人模板:这个是学数据结构时,最开始学的二分代码,结果后来把这种方法忘了,还是不能忘本。。
用ans记录最终结果即可。
ans = -1; //-1表示没找到
while(l <= r) {
int mid = l + (r - l) / 2; //防止溢出
if(check(mid)) {
ans = mid;
l = mid + 1;
}
else {
r = mid - 1;
}
}
return ans;
2、递减,找第一个位置
代码1:朴实版:(这种打法不需要额外确认边界条件,用ans即可判断)
ans = -1;//-1表示没找到
while(l <= r) {
int mid = l + (r - l) / 2;//防止溢出
if(check(mid)) {
ans = mid;
r = mid - 1;
}
else {
l = mid + 1;
}
}
return ans;
代码2:单边界移动**(这种打法需要额外确认边界条件,需要最后再check一下)**
while(l < r) {
int mid = l + (r - l) / 2;//防止溢出
if(check(mid)) { //if(a[mid] > mid)
l = mid + 1;
}
else {
r = mid;
}
}
int ans = -1;//-1表示没找到
if(cheack(l))ans = l;
return ans;
3、既有递增,又有递减,判断峰值(下面的代码假设左边递增,右边递减):
while (l < r) {
int mid = (l + r) / 2; //防止溢出
if (a[mid] > a[mid + 1]) //如果右边递减,峰值只能在左边
r = mid;
else
l = mid + 1;
}
return l;