目录
二分查找最容易出错的就是边界条件的处理。在遇到这个问题,出错并纠结了很多次后,终于下定决心攻克这个问题,让下次遇到二分问题能够游刃有余。
1 查找到了就返回
这个是最简单的,中间值大于target就往左,小于target就往右,等于target就找到了。
leetcode例题:69. x 的平方根
2 查找左边界
比如a=[2,3,3,4,6],寻找第一个值为3的下标,
开始left=0,right=4,mid=2,第一次找到2下标,
right=2,left=0,mid=1,也就是说找到了一个值为3的下标,不知道它是不是第一个,就把它放在右端,
若前面还有值为3的,又把前面的设置为右端,然后right=1
终止条件有些人习惯left<=right,这样循环结束时left=right+1。但我还是喜欢left<right这个形式,这样循环结束时left==right,然后判断nums[left]或nums[right]是否是target,如果是就找到了, 不是就是target不存在。
class Solution:
def minEatingSpeed(self, nums: List[int], target: int) -> int:
left,right=1,len(nums)-1
while left<right:
mid=(left+right)//2#mid值偏左
if nums[mid]>=target:
right=mid#因为找左边界,对可能的右边界就宽容
else:
left=mid+1
return left
leetcode例题:
3 查找右边界
class Solution:
def minEatingSpeed(self, nums: List[int], target: int) -> int:
left,right=1,len(nums)-1
while left<right:
mid=(left+right+1)//2#mid值偏右
if nums[mid]<=target:
left=mid#因为找右边界,对可能的左边界就宽容
else:
right=mid-1
return left
4 旋转数组
4.1 找旋转数组中的最小值
思路:
如果nums[mid]<nums[right],说明右边有序,最小值不在mid上就在左边,所以right=mid
如果nums[mid]>nums[right],说明左边有序,最小值在右边,left=mid+1
如果nums[mid]==nums[right],不能判断哪边有序,right-=1
无重复数
有重复数
4.2 找旋转数组中的特定值
思路:
-
如果nums[mid]<nums[right],说明右边有序,target不在右边就在左边
-
如果nums[mid]>nums[right],说明左边有序,target不在左边就在右边
-
如果nums[mid]==nums[right],不能判断哪边有序,right-=1即可
#找旋转数组中的特定值是否存在代码
class Solution:
def search(self, nums: List[int], target: int) -> bool:
left,right=0,len(nums)-1
mid=0
if len(nums)==0:return False
while left<right:
mid=(left+right)//2
if nums[mid]==target:return True
if nums[mid]<nums[right]:
if target>nums[mid] and target<=nums[right]:
left=mid+1
else:
right=mid-1
elif nums[mid]>nums[right]:
if target>=nums[left] and target<nums[mid]:
right=mid-1
else:
left=mid+1
else:
right-=1
return nums[right]==target