二分法的边界问题
二分法是一种快速的搜索策略,在有序数组中选取中间位置进行判断,每一轮的搜索可以删除一半的数据域,从而将搜索的时间复杂度降为
O
(
l
o
g
n
)
O(log n)
O(logn)。但在利用二分法编写程序时,尤其需要注意二分法的边界条件,属于容易出错的细节问题。
一般二分法有两种方式实现对边界的控制,分别是左闭右闭和左闭右开。
方式一:左闭右闭
如果二分查找的范围是一个左闭右闭区间[left,right],while循环的结束控制条件应该是left<=right,此时需要使用<=,因为left==right在闭区间内是有意义的。
一轮查找后对边界进行收缩,如果nums[mid]<target,则目标一定在mid之后,设定left=mid+1;若nums[mid]>target,则目标一定在mid之前,设定right=mid-1。
def search(nums, target):
while left <= right:
mid = left + (right - left) // 2
if nums[mid] == target:
return mid
if nums[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
方式二:左闭右开
如果二分查找的范围是一个左闭右开区间[left,right),while循环的结束控制条件应该是left<right,此时需要使用<,因为left==right在左闭右开区间内是没有意义的。
一轮查找后对边界进行收缩,如果nums[mid]<target,则目标一定在mid之后,设定left=mid+1;若nums[mid]>target,则目标一定在mid之前,但由于right是不可取到的,设定right=mid。
def search(nums, target):
while left < right:
mid = left + (right - left) // 2
if nums[mid] == target:
return mid
if nums[mid] < target:
left = mid + 1
else:
right = mid
return -1
例题
704.二分查找
给定一个n
个元素有序的(升序)整型数组nums
和一个目标值target
,写一个函数搜索nums
中的target
,如果目标值存在返回下标,否则返回-1
。示例1:
输入:nums = [-1,0,3,5,9,12], target = 9
输出:4示例2:
输入:nums = [-1,0,3,5,9,12], target = 2
输出:-1提示:
- 你可以假设
nums
中的所有元素是不重复的。n
将在[1,10000]
之间。nums
的每个元素都将在[-9999,9999]
之间。
写法一:左闭右闭
class Solution:
def search(self, nums: List[int], target: int) -> int:
left, right = 0, len(nums)-1
while left <= right:
mid = left + (right - left) // 2
if nums[mid] == target:
return mid
if nums[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
写法二:左闭右开
class Solution:
def search(self, nums: List[int], target: int) -> int:
left, right = 0, len(nums)
while left < right:
mid = left + (right - left) // 2
if nums[mid] == target:
return mid
if nums[mid] < target:
left = mid + 1
else:
right = mid
return -1