Leetcode演算法——33、查詢有序旋轉陣列
阿新 • • 發佈:2018-11-08
給定一個數組,這個陣列是由一個升序陣列進行左旋或右旋若干次得到的。
比如,[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))