聽說你還不會UAF?
阿新 • • 發佈:2021-07-16
一個包含重複元素的升序陣列在經過旋轉之後,可以得到下面視覺化的折線圖:
其中橫軸表示陣列元素的下標,縱軸表示陣列元素的值。圖中標出了最小值的位置,是我們需要查詢的目標。
我們考慮陣列中的最後一個元素 x:在最小值右側的元素,它們的值一定都小於等於 x;而在最小值左側的元素,它們的值一定都大於等於 x。因此,我們可以根據這一條性質,通過二分查詢的方法找出最小值。
在二分查詢的每一步中,左邊界為 low,右邊界為 high,區間的中點為 pivot,最小值就在該區間內。我們將中軸元素 numbers[pivot] 與右邊界元素 numbers[high] 進行比較,可能會有以下的三種情況:
第一種情況是 numbers[pivot]<numbers[high]。如下圖所示,這說明 numbers[pivot] 是最小值右側的元素,因此我們可以忽略二分查詢區間的右半部分。
第二種情況是 numbers[pivot]>numbers[high]。如下圖所示,這說明 numbers[pivot] 是最小值左側的元素,因此我們可以忽略二分查詢區間的左半部分。
第三種情況是 numbers[pivot]==numbers[high]。如下圖所示,由於重複元素的存在,我們並不能確定 numbers[pivot] 究竟在最小值的左側還是右側,因此我們不能莽撞地忽略某一部分的元素。我們唯一可以知道的是,由於它們的值相同,所以無論 numbers[high] 是不是最小值,都有一個它的「替代品」numbers[pivot],因此我們可以忽略二分查詢區間的右端點。
當二分查詢結束時,我們就得到了最小值所在的位置。
class Solution { public: int minArray(vector<int>& numbers) { int n =numbers.size(); int l = 0, r = n - 1; while (l < r) { int mid = l + r >> 1; if(numbers[mid] < numbers[r]) r = mid; else if(numbers[mid] > numbers[r]) l = mid + 1; else r--; } return numbers[l]; } };