對於二分法中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;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM