首先要明确二分查找算法如何实现,是采用左闭右闭还是左闭右开
左闭右闭
第⼀种写法,我们定义 target 是在⼀个在左闭右闭的区间⾥,也就是 [left, right] (这个很重要⾮常重要)。
区间的定义这就决定了⼆分法的代码应该如何写,因为定义 target在 [left, right]区间,所以有如下两点:
while (left <= right) 要使⽤ <= ,因为left == right是有意义的,所以使⽤ <=
if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]⼀定不是target,那么接
下来要查找的左区间结束下标位置就是 middle - 1
左开右闭
如果说定义 target 是在⼀个在左闭右开的区间⾥,也就是[left, right) ,那么⼆分法的边界处理⽅式则截然不同。
有如下两点:
while (left < right),这⾥使⽤ < ,因为left == right在区间[left, right)是没有意义的
if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻
找,⽽寻找区间是左闭右开区间,所以right更新为middle,即:下⼀个查询区间不会去⽐较nums[middle]
复杂度:对于长度为n的数组,最坏情况下需要进行log₂n次比较操作。每次操作的时间复杂度为O(1),因此总的时间复杂度为对数阶O(log n)
74. 搜索二维矩阵

python
class Solution(object):
def searchMatrix(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
m=len(matrix)#行
n=len(matrix[0])#列
#每一个编号可以为n*行号+列号
left=0
right=m*n-1
while(left<=right):
middle=(left+right)/2
loclm,locrm=middle/n,middle-middle/n*n
#loclm,locrm=middle//n,middle%n
if matrix[loclm][locrm]==target:
return True
elif matrix[loclm][locrm]>target:
right=middle-1
else:
left=middle+1
return False
34. 在排序数组中查找元素的第一个和最后一个位置
34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

相当于找一个框可以包住target数组,比如[5,7,7,8,8,10]target=8的例子就是希望能找到[7,8,8,10]这个框
寻找target在数组里的左右边界,有如下三种情况:
- 情况一:target 在数组范围的右边或者左边,例如数组{3, 4, 5},target为2或者数组{3, 4, 5},target为6,此时应该返回{-1, -1}
- 情况二:target 在数组范围中,且数组中不存在target,例如数组{3,6,7},target为5,此时应该返回{-1, -1}
- 情况三:target 在数组范围中,且数组中存在target,例如数组{3,6,7},target为6,此时应该返回{1, 1}
这三种情况都考虑到,说明就想的很清楚了。
接下来,在去寻找左边界,和右边界了。
采用二分法来去寻找左右边界,两个二分来寻找左边界和右边界。

为了避免上面的情况,所以需要初始化为-2而不是-1
rightborder=-2,leftborder=-2
python
class Solution(object):
def searchRange(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
left=0
right=len(nums)-1
#左闭右闭查找方式
#相当于找一个框可以包住target数组,比如[5,7,7,8,8,10]target=8的例子就是希望能找到[7,8,8,10]这个框
rightborder=-2
leftborder=-2
#leftborder查找
while left<=right:
middle=(left+right)/2
if target>nums[middle]:
left=middle+1
elif target<=nums[middle]:
right=middle-1
#这里更新跟随等号走,并且更新为right而不是middle
leftborder=right
#rightborder查找
#重新初始化
left=0
right=len(nums)-1
while left<=right:
middle=(left+right)/2
if target>=nums[middle]:
left=middle+1
rightborder=left
elif target<nums[middle]:
right=middle-1
if rightborder ==-2 or leftborder ==-2:
return [-1,-1]
#区间长度至少为2
elif rightborder-leftborder>1:
return [leftborder+1,rightborder-1]
else:
return [-1,-1]