据说,只有 10 % 10\% 10%的程序员能把二分写对
算法思路:假设目标值在闭区间 [ l , r ] [l, r] [l,r]中, 每次将区间长度缩小一半,当 l = r l = r l=r时,我们就找到了目标值。
第一种:
当我们将区间 [ l , r ] [l, r] [l,r]划分成 [ l , m i d ] [l, mid] [l,mid]和 [ m i d + 1 , r ] [mid + 1, r] [mid+1,r]时,其更新操作是 r = m i d r = mid r=mid或者 l = m i d + 1 l = mid + 1 l=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 , m i d − 1 ] [l, mid - 1] [l,mid−1]和 [ m i d , r ] [mid, r] [mid,r]时,其更新操作是 r = m i d − 1 r = mid - 1 r=mid−1或者 l = m i d l = mid l=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;
}
总结
具体还得实际来,没有万能的模板。