二分查找
二分查找
二分查找可根据不同的区间划分分为三种,每种区间都有其特定的边界划分,而二分查找最重要的就是边界划分
三种不同划分区间的二分查找(mid下取整,偶数个时取左边为mid)
[l,r]闭区间
#判断条件,终止时:l=r+1,而边界就在(r,r+1)之间(是l,r中间),如右侧为满足条件,则[r+1:]均满足条件
while(l<=r):
#l,r取值,取值时是不符合条件的一侧;确定不符合条件,排除搜索集合外
#(以搜索目标target为例易理解,但是如果是第一个>x的值这种,右侧的开区间取值是可能成为答案值的,主要在返回的时候处理,根据边界取答案)
l=mid+1
r=mid-1
[l,r) 左闭右开
#判断条件,终止时:l=r,而边界就在l左侧之间,如右侧为满足条件,则[l:]均满足条件
while(l<r):
#l,r取值,取值时是不符合条件的一侧;确定不符合条件,排除搜索集合外
l=mid+1
r=mid
(l,r) 开区间
#判断条件,终止时:l+1=r,而边界就在l右侧之间(即l,r中间),如右侧为满足条件,则[r:]均满足条件
while(l+1<r):
#l,r取值,取值时是不符合条件的一侧;确定不符合条件,排除搜索集合外
l=mid
r=mid
bisect示例代码
区间选择[l,r),因为是插入,可选位置为[0,n]
#a:int[] x:int
# 查找第一个>=x的位置
def bisect_left(a, x, lo=0, hi=None):
if lo < 0:
raise ValueError('lo must be non-negative')
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
# Use __lt__ to match the logic in list.sort() and in heapq
if a[mid] < x: lo = mid+1
else: hi = mid
#查找第一个>=x的位置,将源码改成判断条件,类似bisect_right
#最后一步[a,a+1),mid取a,mid满足条件[a,a),mid不满足条件取[a+1,a+1),最后的lo一定是满足条件的,边界在lo的左边
if a[mid]>=x: hi=mid #右侧是满足条件的,如最后一步左侧不满足条件,也是能取得lo=mid+1的上一次的右侧的
else:lo=mid+1
#边界在lo的左侧,即[lo:]都满足条件,lo是第一个满足条件的
return lo
## 查找第一个>x的位置
def bisect_right(a, x, lo=0, hi=None):
if lo < 0:
raise ValueError('lo must be non-negative')
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
# Use __lt__ to match the logic in list.sort() and in heapq
if x < a[mid]: hi = mid #a[mid]>x
else: lo = mid+1
return lo

浙公网安备 33010602011771号