二分概述
二分就是能比暴力枚举能用更少的时间复杂度找出边界点。
一个长为n的数组,(l,r分别为左右边界)具有某种性质,能够将数组分成两半,例如左边满足右边不满足。
二分思想 模板
现求左边部分的边界:mid=l+r>>1+1,if(check(mid)==true),即mid在左边部分,令 l=mid;if(check(mid)==false),即mid在右边部分,r=mid-1;
现求右边部分边界:mid=l+r>>1;if(check(mid)==true)即mid在左边部分,l=mid+1;if(check(mid)==false),即mid在右边部分,r=mid;
这是两种求边界值的模板。
question
具体第一种模板为什么mid+1,没仔细推过,听讲是怕出现l与r出现相邻的情况。
代码:
bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
思考:
最后return l和r都可以,因为二分到最后,l==r,但是不能是mid,因为更新边界的时候,是l=mid+1或者r=mid-1;