1. 程式人生 > >Leetcode演算法——33、查詢有序旋轉陣列

Leetcode演算法——33、查詢有序旋轉陣列

給定一個數組,這個陣列是由一個升序陣列進行左旋或右旋若干次得到的。

比如,[0,1,2,4,5,6,7] 可能會變為 [4,5,6,7,0,1,2]

給定一個目標值,去陣列中查詢這個值。如果找到,則返回索引,否則返回-1。

可以假設陣列中沒有重複值。

示例:
Example 1:
Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4
Example 2:

Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1

思路

如果沒有旋轉,就是有序陣列,那麼查詢一個元素的位置有一個經典的方法——二分法。

本題對有序陣列進行了旋轉,因此二分法也需要做出一些調整,主要體現在選擇左半區域還是右半區域作為下一次查詢的子串。

對於經典的二分法,如果目標值小於中位數,則下一次查詢選擇左半區域,否則,選擇右半區域。

對於本題,以圖為例,陣列首元素的索引為 l,尾元素的索引為 u,中位數的索引為 mid。由於旋轉而得到的,因此可以看到有一個低谷,是最高值和最低值相鄰的地方。
在這裡插入圖片描述

選擇下一次搜尋的區域時,還需要考慮中位數和首尾兩個元素之間的大小關係:

  • 如果 nums[mid] > nums[l],則說明低谷位於右半部分。
    這時,如果 nums[l] < target < nums[mid],則需要選擇左半區域,否則選擇右半區域。
  • 如果 nums[mid] < nums[l],則說明低谷位於左半部分。
    這時,如果 nums[mid] < target < nums[u],則需要選擇右半區域,否則選擇左半區域。

演算法復的時間複雜度與經典二分法相同,為 O(logn)。

python實現

def search(nums, target):
    """
    :type nums: List[int]
    :type target: int
    :rtype: int
    二分法。
    """
    
    if not nums:
        return
-1 l, u = 0, len(nums)-1 while(l <= u): # 長度為1或2 if u - l <= 1: try: return l + nums[l:u+1].index(target) except: return -1 mid = int((l + u) / 2) if nums[mid] == target: return mid if nums[mid] > nums[l]: # 說明mid落在了左半部分 if target > nums[mid]: l = mid + 1 elif target >= nums[l]: u = mid-1 else: l = mid + 1 else: if target < nums[mid]: u = mid - 1 elif target <= nums[u]: l = mid + 1 else: u = mid - 1 if '__main__' == __name__: nums = [4,5,6,7,0,1,2] target = 0 print(search(nums, target))