对于二分法中mid取值以及边界迭代边界问题的理解

注:模板来自 acwing yxc

整数二分模板:
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;
}
  二分的疑惑主要是在mid的取值,以及l和r的迭代。
  这里先讨论第二个问题,先看模板一,这是在找左边界,由于如果mid这个点满足我们的条件,说明我们要求的边界点在mid点或者mid左边,但是不可能小于l,所以取区间[l,mid];如果mid点不满足条件说明边界点在mid右边,但不可能等于mid或者大于r,但是可能取mid+1,所以我们取[mid+1,r];然后看模板二,这是在找右边界,如果mid满足条件,那么右边界可能在mid点或者大于mid小于等于r,所以我们取[mid,r];如果mid不满足条件,说明边界点在mid左边,所以取[l,mid-1];
第一个问题:首先明确两点:
  ①mid值不同是为了防止死循环,而死循环的条件只有两次迭代后,l或者r的值仍不改变。
  ②l,mid,r都是整数,说明如果存在l<mid<r这种类似的关系,不可能通过l或者mid加上一个小数而使得其中某一个<号变成=号。
  而我们知道(l+r>>1)和(l+r+1>>1)不可能小于l或者大于r,且第一种情况满足的是l<=mid<r,但我们每次迭代l的时候取的是mid+1,说明两次迭代后的l不可能相等,因为l<mid+1嘛,又因为mid<r,而迭代r的方式是r=mid,说明r每次都在变小,不可能陷入死循环。第二种情况满足的是l<mid<=r,我们迭代l的时候,令l=mid这样l一定变大,令r=mid-1这样r一定变小,不会陷入死循环。
  这两种mid取值的根本原因是c++的向下取整属性,即int(l+r)/2<double(l+r)/2;

上一篇:关于 Let's Encrypt 免费证书过期的事情(-107(token check timeout)微信公众号无法验证http通过


下一篇:洛谷 P1379 八数码难题