据说,只有10%10\%10%的程序员能把二分写对
算法思路:假设目标值在闭区间[l,r][l, r][l,r]中, 每次将区间长度缩小一半,当l=rl = rl=r时,我们就找到了目标值。
第一种:
当我们将区间[l,r][l, r][l,r]划分成[l,mid][l, mid][l,mid]和[mid+1,r][mid + 1, r][mid+1,r]时,其更新操作是r=midr = midr=mid或者l=mid+1l = mid + 1l=mid+1;,计算mid时不需要加1。
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
return l;
}
第二种
当我们将区间[l,r][l, r][l,r]划分成[l,mid−1][l, mid - 1][l,mid−1]和[mid,r][mid, r][mid,r]时,其更新操作是r=mid−1r = mid - 1r=mid−1或者l=midl = midl=mid;,此时为了防止死循环,计算mid时需要加1。
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;
}
第三种
白书上的,也是我最常用的,对于整数域,先将范围统一往左右各扩大一位,然后对应的二分即可。
int bsearch_2(int l, int r)
{
l--,r++;
while (l+1 < r)
{
int mid = l + r >> 1;
if (check(mid)) l = mid;
else r = mid ;
}
return l;
}
对于实数域上的二分
int bsearch_2(double l, double r)
{
double eps=1e(-k-2);
while (r-l > eps)
{
double mid = l + r >> 1;
if (check(mid)) l = mid;
else r = mid ;
}
return l;
}
int bsearch_2(double l, double r)
{
for(int i=0;i<100;i++)
{
double mid = l + r >> 1;
if (check(mid)) l = mid;
else r = mid ;
}
return l;
}
总结
具体还得实际来,没有万能的模板。