本题要点就是:只在有上升顺序的那一端做二分查找,妥妥的能解决,并且思路清晰,虽然思路很简单,但是二分查找看的是细节,判断语句中使用大于等于,还是大于,或者使用小于等于还是小于,这些写错一个就可能会要了你的命!
代码实现:
class Solution:
def search(self, nums: List[int], target: int) -> int:
n = len(nums)
left,right =0,n-1
while left<=right:
mid = left+(right-left)//2
if nums[mid]==target:
return mid
elif nums[left]<=nums[mid]:
if nums[left]<=target<nums[mid]:
right=mid-1
else:
left = mid+1
else:
if nums[mid]<taregt<=nums[right]:
left = mid+1
else:
right=mid- 1
return -1
自己每个一段时间做这道题的时候经常有以下几个地方会写错,经过这次整理之后希望以后不会写错了
- 为什么是 while left <= right:, 在与正常的二分查找模板一样,我们要考虑当left和right相遇时,此时对应的值是否是target,所以不能把这个数给刨除掉
- 为什么是 nums[left]<=nums[mid],这里我们考虑一个例子[2,1],target=1,此时对于这种情况,mid=0,如果是nums[left]<nums[mid],那么会进入下一个else,进而right=mid-1,此时,right=-1,return -1,导致第二个值无法被查询,所以这也是当mid==left时,需要判断一下
- 为什么是nums[mid]<target<=nums[right] 因为前面判断过,此时 nums[mid]肯定不等于target,如果此时右边是递增的,只需要考虑nums[mid+1]就可以了,所以写成这样也是可以的nums[mid+1]<=target<=nums[right]
这道题的思路就是:使用mid值和right比较,这一点相当重要了
class Solution:
def minArray(self, numbers: List[int]) -> int:
n = len(numbers)
left, right = 0,n-1
while left<right:
mid = left+(right-left)//2
if numbers[mid]<numbers[right]:
# 右侧递增,但是mid处可能是最小值
right=mid
elif numbers[mid]==numbers[right]:
# 就算right是最小值,把它过滤掉还有mid呢
right-=1
else:
# 左侧递增,那么mid肯定不是最小值
left = mid+1
return numbers[left]
同样的列举几个疑问你要是全理解了,估计这道题你就彻底懂了
- 为什么while left<right:?很简单,这道题没有target,没有一个明确比较的点,我们只能不断地缩小范围,逼近直到确定这个最小值点,如何确定?那么当然是当left==right的时候了,那么此时需要返回nums[left]或者nums[right]
- 为什么numbers[mid]>numbers[right],要right=mid,因为我们只能得到mid的右侧包括mid在内组成的是一个递增数列,然而并不能确定mid处是否是一个最小值,即mid处可能是一个最小值
- 为什么要left = mid+1?因为走到这一步可以明确,mid左侧,包括mid处是一个递增数列,那么递增的数列不可能存在最小值,那么可以执行left = mid+1