二分查找模板(轉載)

原文轉自https://www.acwing.com/blog/content/307/

一、查找精確值

從一個有序數組中找到一個符合要求的精確值(如猜數遊戲)。如查找值爲Key的元素下標,不存在返回-1。

//這裏是left<=right。
//考慮這種情況:如果最後剩下A[i]和A[i+1](這也是最容易導致導致死循環的情況)首先mid = i,
//如果A[mid] < key,那麼left = mid+1 = i +1,如果是小於號,則A[i + 1]不會被檢查,導致錯誤
int left = 1,right = n;
while(left <= right)
{
   //這裏left和right代表的是數組下標,所有沒有必要改寫成mid = left + (right - left)/2;
  //因爲當代表數組下標的時候,在數值越界之前,內存可能就已經越界了
  //如果left和right代表的是一個整數,就有必要使用後面一種寫法防止整數越界
        int mid = (left + right) / 2;
    if(A[mid] == key)
      return mid;
    else if(A[mid] > key)//這裏因爲mid不可能是答案了,所以搜索範圍都需要將mid排除
      right = mid - 1;
    else
      left = mid + 1;
}
return -1;

二、查找大於等於/大於key的第一個元素
這種通常題目描述爲滿足某種情況的最小的元素。

int left = 1,right = n;
while(left < right)
{
  //這裏不需要加1。我們考慮如下的情況,最後只剩下A[i],A[i + 1]。
  //首先mid = i,如果A[mid] > key,那麼right = left = i,跳出循環,如果A[mid] < key,left = right = i + 1跳出循環,所有不會死循環。
  int mid = (left + right) / 2;
  if(A[mid] > key)//如果要求大於等於可以加上等於,也可以是check(A[mid])
    right = mid;
  //因爲找的是大於key的第一個元素,那麼比A[mid]大的元素肯定不是第一個大於key的元素,因爲A[mid]已經大於key了,所以把mid+1到後面的排除
  else
    left = mid + 1;
  //如果A[mid]小於key的話,那麼A[mid]以及比A[mid]小的數都需要排除,因爲他們都小於key。不可能是第一個大於等於key的元素,
}

三、查找小於等於/小於key的最後一個元素
這種通常題目描述爲滿足某種情況的最大的元素。如Leetcode69題,求sqrt(x)向下取整就是這種模板。

int left = 1, right = n;
while(left < right)
{
  //這裏mid = (left + right + 1) / 2;
  //考慮如下一種情況,最後只剩下A[i],A[i + 1],如果不加1,那麼mid = i,如果A[mid] < key,執行更新操作後,left = mid,right = mid + 1,就會是死循環。
  //加上1後,mid = i + 1,如果A[mid] < key,那麼left = right = mid + 1,跳出循環。如果A[mid] > key,left = mid = i,跳出循環。
  int mid = (left + right + 1) / 2;
  if(A[mid] < key)
    left = mid;//如果A[mid]小於key,說明比A[mid]更小的數肯定不是小於key的最大的元素了,所以要排除mid之前的所有元素
  else
    right = mid - 1;//如果A[mid]大於key,那麼說明A[mid]以及比A[mid]還要大的數都不可能小於key,所以排除A[mid]及其之後的元素。
}

二分細節經常寫錯,就轉了一個模板方便查閱

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章