把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如,數組 [3,4,5,1,2] 爲 [1,2,3,4,5] 的一個旋轉,該數組的最小值爲1。
示例 1:
輸入:[3,4,5,1,2]
輸出:1
示例 2:
輸入:[2,2,2,0,1]
輸出:
兩種思路:
O(n)
複雜度:遍歷一遍,尋找降序點,輸出降序點值,如果找不到,輸出列表的首元素O(logn)
複雜度:二分查找,注意分治方法,必須保證每次的規模都是減小的,而且要注意最後輸出的是值而不是轉折點的索引
# 第一種思路
def min_ele(nums):
for i in range(1, len(nums)):
if nums[i - 1] > nums[i]:
return nums[i]
return nums[0]
# 第二種思路
def min_element(nums):
i = 0
j = len(nums) - 1
while i < j:
mid = (i + j) // 2 # 左二分點,必有i <= mid < j
if nums[mid] < nums[j]:
j = mid
elif nums[mid] > nums[j]:
i = mid + 1 # 必須是mid + 1, 不能是mid,保證規模減小
else:
j -= 1 # 分析見後文
return nums[i]
關於nums[mid] == nums[j]
的分析:
- 如果
mid
在左序列,則nums
在[i, mid]
和j
上的值都是相等的。進一步,若j
不是旋轉點,則旋轉點在[i, j - 1]
中。若j
是旋轉點,則[i, j - 1]
爲遞增序列,繼續走下去會輸出序列首,並且序列首的值和旋轉點的值相等。 - 如果
mid
在右序列,則旋轉點在[i, mid]
而mid < j
,從而在[i, j - 1]
中。
實現代碼中的問題:
- 二分法三點:改變左右索引,保證規模減小,並且最終值在區間中。
- 通常使用
while i < j
的模式實現。如果用遞歸寫,也可以,但是比較麻煩,邏輯上也不好處理變化。 - 比較時使用起點或者終點作爲基準點,而不是中間點周圍的點如
mid + 1
, 那樣會把問題搞複雜。 - 對於
nums[mid] == nums[j]
的討論具有技巧,注意把握。