一、查找精確值
從一個有序數組中找到一個符合要求的精確值(如猜數游戲)。如查找值為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/