二分查找

二分查找

二分查找可根据不同的区间划分分为三种,每种区间都有其特定的边界划分,而二分查找最重要的就是边界划分

三种不同划分区间的二分查找(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

posted @ 2026-09-22 11:03  在哪还好吗  阅读(4)  评论(0)    收藏  举报