iT邦幫忙

0

leetcode with python:33. Search in Rotated Sorted Array

題目:

There is an integer array nums sorted in ascending order (with distinct values).

Prior to being passed to your function, nums is possibly rotated at an unknown pivot index k (1 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] (0-indexed). For example, [0,1,2,4,5,6,7] might be rotated at pivot index 3 and become [4,5,6,7,0,1,2].

Given the array nums after the possible rotation and an integer target, return the index of target if it is in nums, or -1 if it is not in nums.

You must write an algorithm with O(log n) runtime complexity.

給定一陣列,該陣列由一升序陣列,值都是獨一無二的,將其前段一部分移至後方構成
ex:[4,5,6,7,0,1,2]為[0,1,2]移到後方構成
題目給定一數(target),若target在陣列內回傳其index,反之回傳-1
限制時間複雜度為O(log n)

題目限制O(log n),第一時間想到二分搜
但這題是比較tricky的二分搜

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        
            
        if nums[-1]==target: #若target即為nums[-1],回傳len(nums)-1
            return len(nums)-1
        
        if nums[0]>target and nums[-1]<target: #若target位於nums[0]和nums[-1]之間,表示target不在該陣列,回傳-1
            return -1
        
        l=0
        r=len(nums)-1
            
        if nums[-1]>target:
            while l<r:
                mid=(l+r)//2
                if nums[mid]>target and nums[mid]<nums[-1]:
                    r=mid-1
                elif nums[mid]==target:
                    return mid
                else:
                    l=mid+1
                     
        else:
            while l<r:
                mid=(l+r)//2
                if nums[mid]<target and nums[mid]>nums[-1]:
                    l=mid+1
                elif nums[mid]==target:
                    return mid
                else:
                    r=mid-1
                    
                    
        if nums[l]==target:
            return l
        else:
            return -1

根據經驗,二分搜常用於排序陣列,但這題的輸入並不是
為了讓我們能運用二分搜
我們可以將題目給的陣列分為兩個部分,被移到後方的部分(s2)和其餘的部分(s1)
以 [4,5,6,7,0,1,2]為例,[4,5,6,7]為s1,[0,1,2]為s2
也就是兩個排序陣列
而我們知道s2元素小於s1的任何元素(因為它們原本是一升序排列的陣列)

我發現可以用陣列最後一數來判斷target會位在s1還是s2
最後一數身為s2最大的數,第一數身為s1最小的數
若target位於nums[0]和nums[-1]之間,表示target不在該陣列,回傳-1
其餘若target大於nums[-1],則target會在s1
若target小於nums[-1],則target會在s2

正常分兩種狀況,target在s1和target在s2
設下限l=0跟上限r=len(nums)-1,mid定義為(1+r)//2

target在s2:
和一般二分搜的作法差不多,但有個特例要注意
若nums[mid]>target但nums[mid]位在s1內
照理來說nums[mid]>target我們應該要把r邊界往下移
但我們已知target在s2,而此時mid在s1內
表示從l到mid這段全部都是s1的範疇,target不可能在這裡
所以我們反倒要將l邊界往上移去除這塊區域

target在s1:
同樣有個類似特例要注意
若nums[mid]< target但nums[mid]位在s2內
一般nums[mid]< target我們應該要把l邊界往上移
但我們已知target在s1,而此時mid在s2內
表示從mid到r這段全部都是s2的範疇,target不可能在這裡
所以我們反倒要將r邊界往下移去除這塊區域

二分搜到最後都沒有mid回傳的話
則檢測l位置的值是否為target
是的話回傳l,不是的話表示target不在此陣列內,回傳-1
最後執行時間41ms(faster than 96.03%)

那我們下題見


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言