旋轉陣列的最小數字(Python and C++解法)
阿新 • • 發佈:2020-06-28
題目:
把一個數組最開始的若干個元素搬到陣列的末尾,我們稱之為陣列的旋轉。輸入一個遞增排序的陣列的一個旋轉,輸出旋轉陣列的最小元素。例如,陣列[3,4,5,1,2] 為 [1,2,3,4,5] 的一個旋轉,該陣列的最小值為1。
示例 1:
輸入:[3,4,5,1,2] 輸出:1
示例 2:
輸入:[2,2,2,0,1] 輸出:0
來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof
思路:
本題需要對二分查詢法靈活運用。本題沒有明確的目標值進行比較,可以將端點numbers[right]看作目標值,進而進行區間判斷。
在正常情況下,對於旋轉之後的陣列,前面的子陣列元素都>=後面的子陣列元素,且最小的元素就是這兩個子陣列的分界點。
特殊情況一:搬移了0個元素,即旋轉之後的陣列還是原來的遞增陣列,此時陣列的特點是numbers[left] <numbers[right].
特殊情況二:numbers[mid] == numbers[right]時,若陣列是[1,0,1,1,1]或[1,1,1,0,1],則不能確定最小值在左邊還是在右邊,只能一步步改變邊界,慢慢縮小範圍。
注意:不能把左端點看做目標值,原因在於這樣不能確定最小值在哪一側:
情況1 :1 2 3 4 5 , arr[mid] = 3. target = 1, arr[mid] > target, 答案在mid 的左側 情況2 :3 4 5 1 2 , arr[mid] = 5, target = 3, arr[mid] > target, 答案卻在mid 的右側
Python解法:
1 class Solution: 2 def minArray(self, numbers: List[int]) -> int: 3 left = 0 4 right = len(numbers) - 1 5 6 if numbers[left] < numbers[right]: # 特殊情況,旋轉0個元素,旋轉前後不變 7 returnnumbers[left] 8 9 while left <= right: 10 mid = left + ((right - left) >> 1) 11 if numbers[mid] < numbers[right]: 12 right = mid # numbers[mid]可能是最小值,所以右邊界不能變 13 elif numbers[mid] > numbers[right]: 14 left = mid + 1 15 else: # 二者相等時,在特殊情況[1,0,1,1,1]或[1,1,1,0,1]時不能確定最小值在左還是在右 16 right -= 1 # 只能一步步更新right,慢慢縮小範圍 17 return numbers[left]
C++解法:
1 class Solution { 2 public: 3 int minArray(vector<int>& numbers) { 4 int left = 0; 5 int right = numbers.size() - 1; 6 7 if(numbers[left] < numbers[right]) // 特殊情況一 8 return numbers[left]; 9 10 while(left <= right) { 11 int mid = left + ((right - left) >> 1); 12 if(numbers[mid] < numbers[right]) 13 right = mid; 14 else if(numbers[mid] > numbers[right]) 15 left = mid + 1; 16 else // 特殊情況二 17 right -= 1; 18 } 19 return numbers[left]; // 需要返回左端點 20 } 21 };