1. 程式人生 > >Leetcode 33 搜尋旋轉排序陣列 思路詳解+反思總結 python實現

Leetcode 33 搜尋旋轉排序陣列 思路詳解+反思總結 python實現

本人一直在努力地積累Leetcode上用Python實現的題,並且會盡力講清每道題的原理,絕不像其他某些部落格簡略地帶過。
如果覺得講的清楚,歡迎關注。


題目:

假設按照升序排序的陣列在預先未知的某個點上進行了旋轉。

( 例如,陣列 [0,1,2,4,5,6,7] 可能變為 [4,5,6,7,0,1,2] )。

搜尋一個給定的目標值,如果陣列中存在這個目標值,則返回它的索引,否則返回 -1 。

你可以假設陣列中不存在重複的元素。

你的演算法時間複雜度必須是 O(log n) 級別。

示例 1:

輸入: nums = [4,5,6,7,0,1,2], target = 0
輸出: 4

示例 2:

輸入: nums = [4,5,6,7,0,1,2]
, target = 3 輸出: -1

思路:首先了解到這道題要求的解法是logn級別。logn與什麼最搭?當然是二分的思想!但是很多朋友可能會說,排序陣列的二分查詢我很熟,但這道題可能經過了旋轉啊。沒錯,這陣列經過旋轉後,形成了2段遞增的序列。我們得先找到2個序列的分界點,將陣列分成2部分分別二分查詢。那麼這道題的難題就成功轉移到如何找到那個分界點。可能很多朋友又會說,直接從後或者從前按順序找,當突然前面的數字比當前大就說明這是斷點嘛!但題目要求logn,按順序找的話是n。

程式碼:

class Solution:
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        #先找到兩個第二個升序陣列的第一項的index
        l = 0
        r = len(nums) -1
        while l < r:
            mid = (l + r)//2
            if nums[mid] > nums[r]:
                l = mid + 1
            else:
                r = mid
        pol = l
        ans = self.binary_search(target, nums[:pol])
        if ans == -1:
            ans = self.binary_search(target, nums[pol:])
            if ans != -1:
                ans += len(nums[:pol])

        return ans
    
    def binary_search(self, target, nums):
        index = -1
        l = 0
        r = len(nums) - 1
        while l <= r:
            mid = (l+r)//2
            if nums[mid] < target:
                l = mid + 1
            elif nums[mid] > target:
                r = mid - 1
            else:
                index = mid
                break
        return index
        
binarysearch是用來對2陣列分別二分查詢的。找斷點比較有意思:我們通過l 和 R 求 mid, 通過比較mid和最右邊的r的值,我們去判斷第二段遞增序列的第一個點。最右邊的r永遠是在遞增序列中,如果num[mid] < num[r],說明我們這個mid與r在同一個遞增序列,我們減少r,令r=mid,縮小範圍去查詢斷點。如果num[mid] > num[r],說明mid與r在2個遞增序列,增大L,令l= mid+1, 不斷逼近斷點。