https://leetcode.com/problems/search-in-rotated-sorted-array/
2020/08/12
题目是在循环有序的数列中查找一个数,要求时间复杂度log(N)。
看到log(N)和有序就想到二分法,所以我最直观的想法是找出分界点,然后对分界点左右两边的有序数列分别做二分。
分界点的寻找,要想满足题目条件,就也一定要用分治法。考虑一段数列以及它的左右端点,其关于分界点的关系可能有三种情况:
1. 在分界点左边
2. 在分界点右边
3. 包含分界点
所以我们考虑这三种情况有什么区别。一段数列nums不包含边界点时,它一定是单调递增的,取任意中点mid,会有nums[left] < nums[mid] < nums[right]。如果包含边界点,那么边界点左边的任意数一定大于边界点右边的任意数,因为数列从边界点开始,一直单调递增到最右,然后又从左边开始递增,所以一定有nums[left] > nums[right]。
这样以来就可以把nums[left] < nums[right]的线段给剪掉,分治法的优化有效。这里还要额外考虑边界点恰好是left或者right的情况。
找出边界点后,对两段有序数列分别二分就行了。貌似还有更简单用一个函数就解决段方法,等想到了来更新。
class Solution:
breakpoint = -1
flag = False
ans = -1
flag2 = False
def search(self, nums: List[int], target: int) -> int:
self.breakpoint = -1
self.flag = False
self.ans = -1
self.flag2 = False
final_ans = -1
self.findStart(nums, 0, len(nums)-1)
if self.breakpoint == -1:
self.findNum(nums, 0, len(nums)-1, target)
final_ans = self.ans
else:
bp = self.breakpoint
self.findNum(nums[:bp], 0, bp-1, target)
if self.ans != -1:
final_ans = self.ans
else:
self.findNum(nums[bp:], 0, len(nums[bp:])-1, target)
if self.ans != -1:
final_ans = bp + self.ans
return final_ans
def findStart(self, nums,left,right):
if left > right or self.flag:
return
mid = int((left+right)/2)
if nums[mid] <= nums[mid - 1]:
self.breakpoint = mid
self.flag = True
return
if nums[left] < nums[right] and (left == 0 or nums[left-1] < nums[left]):
return
self.findStart(nums,left,mid-1)
self.findStart(nums,mid+1,right)
def findNum(self, s, left, right, target):
if left > right or self.flag2:
return
mid = int((left+right)/2)
if s[mid] == target:
self.ans = mid
self.flag2 = True
return
if s[mid] < target:
self.findNum(s, mid+1, right, target)
else:
self.findNum(s, left, mid-1, target)