二分查找模板


一、查找精確值

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

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

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

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

三、查找小於等於/小於key的最后一個元素

這種通常題目描述為滿足某種情況的最大的元素。如Leetcode69題,求sqrt(x)向下取整就是這種模板。

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

四、總結
最后兩種情況的循環跳出條件是left<right,為什么不是小於等於呢?因為我們的區間變換思路是不斷的舍去不可能是解的區間,最后只剩下一個數就是我們的解。而第一種情況就算最后只剩一個數也有可能不是解,所以需要使用小於等於。

查找精確值,循環條件是小於等於;查找滿足情況的最大最小值,循環條件是小於。
查找滿足條件的最大數,mid = (right + left + 1) / 2;查找滿足條件的最小數,mid = (right + left)/2
mid = left + (right - left) / 2,不是適用於所有的情況。
如果存在沒有解的情況,比如從[1,2,3,4,5]找出大於等於6的第一個數,我們只需要將最后剩下的數單獨進行一次判斷就可以了。

 

該文章出自於 https://www.acwing.com/blog/content/307/


免責聲明!

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



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