題目描述
把一個數組最開始的若干個元素搬到數組的末尾,我們稱之為數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如,數組 [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
解答方法
方法一:二分法
思路
-
循環二分: 設置 left,right指針分別指向 numbers 數組左右兩端,m = (left + right) // 2為每次二分的中點( "http://" 代表向下取整除法,因此恒有
),可分為以下三種情況:
當 numbers[m] > numbers[right]時: m 一定在 左排序數組 中,即最小值 x 一定在 [m + 1,right]閉區間內,因此執行left=m+1;
當 numbers[m] < numbers[right] 時: m一定在 右排序數組 中,即最小值x 一定在[left, m]閉區間內,因此執行right=m;
當 numbers[m] == numbers[right] 時: 無法判斷m 在哪個排序數組中,即無法判斷旋轉點 x 在 [left, m] 還是 [m+1,right] 區間中。解決方案: 執行right=right?1 縮小判斷范圍 (分析見以下內容) 。 -
返回值: 當 left = right時跳出二分循環,并返回 numbers[left] 即可。
參考:https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/solution/mian-shi-ti-11-xuan-zhuan-shu-zu-de-zui-xiao-shu-3/
代碼
class Solution:
def minArray(self, numbers: List[int]) -> int:
if len(numbers) == 0:
return
left = 0
right = len(numbers)-1
while left<right:
mid = left + (right-left)//2
if numbers[mid] > numbers[right]:
left = mid + 1
elif numbers[mid] < numbers[right]:
right = mid
else:
right -= 1
return numbers[left]
時間復雜度
O(log N) : 在特例情況下(例如 [1, 1, 1, 1]),會退化到 O(N)。
空間復雜度
O(1) :left , right , mid 指針使用常數大小的額外空間。