(python版)《劍指Offer》JZ06:旋轉陣列的最小數字

龍共日堯發表於2020-12-14

牛客
LeetCode
在這裡插入圖片描述

【思路1】本質就是求解陣列最小值

class Solution:
    def minArray(self, numbers: List[int]) -> int:
        return min(numbers)

【思路2】二分法

由於原始陣列是遞增,那麼旋轉之後,旋轉點左右的兩部分仍然是遞增的
這裡記原始陣列中旋轉點左側的陣列為 A,原始陣列中旋轉點右側的陣列為 B
旋轉之後有原來的 AB 變成了 BA

演算法流程

  • 初始化: 宣告 l, r雙指標分別指向 nums 陣列左右兩端;
  • 迴圈二分
  • 返回值當 l = r 時跳出二分迴圈,並返回 旋轉點的值 nums[l] 即可。
class Solution:
    def minArray(self, numbers: List[int]) -> int:
        l, r = 0, len(numbers) - 1
        while l < r:
            mid = (l + r) // 2
            if numbers[mid] > numbers[r]:
                # 說明mid在原來的 B 部分,l在mid基礎上 往前一步
                l = mid + 1
            elif numbers[mid] < numbers[r]:
                # 說明mid在A部分,mid做為新的終點r
                r = mid
            else: 
            	# 無法判斷 mm 在哪個排序陣列中,執行 r = r - 1j=j−1 縮小判斷範圍
                r -= 1
        return numbers[l]
'''
作者:LotusPanda
連結:https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/solution/xiong-mao-shua-ti-python3-er-fen-fa-by-lotuspanda/
來源:力扣(LeetCode)
'''

當 numbers[mid] = numbers[r], 一定有區間 [l, m]內所有元素相等 或 區間 [m, r] 內所有元素相等(或兩者皆滿足)。對於尋找此類陣列的最小值問題,可直接放棄二分查詢,而使用線性查詢替代

即 
else:
	return min(numbers[i:j])

作者:Krahets
連結:https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/5055b1/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

補充思考: 為什麼本題二分法不用 nums[mid] 和 nums[l] 作比較?

  • 二分目的是判斷 m 在哪個排序陣列中,從而縮小區間。而在 nums[mid] > nums[l] 情況下,無法判斷 m 在哪個排序陣列中。本質上是由於 j 初始值肯定在右排序陣列中; i 初始值無法確定在哪個排序陣列中。舉例如下:

    對於以下兩示例,當 l = 0, r = 4, m = 2 時,有 nums[mid] > nums[l] ,而結果不同。
    [1, 2, 3, 4 ,5] 旋轉點 x = 0 : m 在右排序陣列(此示例只有右排序陣列);
    [3, 4, 5, 1 ,2] 旋轉點 x = 3 : m 在左排序陣列。

    連結:https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/5055b1/

相關文章