这道题是33. Search in Rotated Sorted Array的升级版,与之前不同的地方是这道题允许存在重复的数字。在之前的33题题解中,我采用的是先找pivot的方法,也就是先找到数组中最大的元素,这样的话,最大的元素两侧都是有序数组,再分别在这两边进行二分查找即可。
然而在这道题中,参考了题解的方法,不用先找pivot。二分归到底就是要知道接下来要去左半边找还是去右半边找,题解中判断的方式就很巧妙。
- 首先得到mid,也就是数组的中间位置。
- 如果中间位置的左边有序,那么就可以通过判断
nums[left] <= target and nums[mid] >= target
来判断target是否在左边,如果不在左边,那就在右边。 - 如果中间位置的右边有序,那么就可以通过判断
nums[mid] <= target and nums[right] >= target
来判断target是否在右边,如果不在右边,那就在左边。 - 知道是在左边还是右边之后,就可以接着二分了。
然而由于有重复元素,所以可能没法通过nums[left] <= nums[mid]
来判断左边是否有序,因为可能会出现1 2 1 1 1
这种情况。所以要对nums[left] == nums[mid]
的情况进行特殊判断,这时候可以直接使得left++
,因为最左边的元素和mid处元素相同,所以这个操作并不会影响最终的结果,而且如果一直弹出最左的和nums[mid]
相同的元素,那么一定会使得数组的nums[left]
与nums[mid]
不同,就可以判断左边是否有序了,或者直接就在弹出的过程中找到了target。
class Solution:
def solve(self, nums: List[int], left: int, right: int, target: int):
while left <= right:
mid = (left+right)>>1
# print(left, right, mid)
if nums[mid] == target:
return True
if nums[mid] == nums[left]:
left += 1
continue
if nums[left] <= nums[mid]:
if nums[left] <= target and nums[mid] >= target:
right = mid-1
else:
left = mid+1
else:
if nums[mid] <= target and nums[right] >= target:
left = mid+1
else:
right = mid-1
return False
def search(self, nums: List[int], target: int) -> bool:
if not nums:
return False
l = len(nums)
return self.solve(nums, 0, l-1, target)