每日一練6.24/6.25——旋轉數組的最小數字

旋轉數組的最小數字

把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如,數組 [3,4,5,1,2] 爲 [1,2,3,4,5] 的一個旋轉,該數組的最小值爲1。

示例 1:
輸入:[3,4,5,1,2]
輸出:1
示例 2:
輸入:[2,2,2,0,1]
輸出:

兩種思路:

  1. O(n) 複雜度:遍歷一遍,尋找降序點,輸出降序點值,如果找不到,輸出列表的首元素
  2. 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]的分析:

  1. 如果mid在左序列,則nums[i, mid]j上的值都是相等的。進一步,若j不是旋轉點,則旋轉點在[i, j - 1]中。若j是旋轉點,則[i, j - 1]爲遞增序列,繼續走下去會輸出序列首,並且序列首的值和旋轉點的值相等。
  2. 如果mid在右序列,則旋轉點在[i, mid]mid < j,從而在[i, j - 1]中。

實現代碼中的問題:

  1. 二分法三點:改變左右索引,保證規模減小,並且最終值在區間中。
  2. 通常使用while i < j的模式實現。如果用遞歸寫,也可以,但是比較麻煩,邏輯上也不好處理變化。
  3. 比較時使用起點或者終點作爲基準點,而不是中間點周圍的點如mid + 1, 那樣會把問題搞複雜。
  4. 對於nums[mid] == nums[j]的討論具有技巧,注意把握。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章