超全的二分查找汇总(lower_bound&upper_bound)

相关内容:

其余练习题1:https://www.cnblogs.com/rnanprince/p/11743414.html
二分查找(倍增法):https://mp.csdn.net/postedit/102811021
其余练习题2:https://www.cnblogs.com/rnanprince/p/11761940.html
————————————————

二分查找

二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。

 • 循环条件到底哪一个
    • start <= end
    • start < end
    • start + 1 < end
• 指针变换到底哪一个?
    • start = mid
    • start = mid + 1
    • start = mid - 1

弄不好就死循环,弄不好边界就失误

怎么办?

模板:

def bin_search(nums, target):
    if not nums or target < nums[0] or target > nums[-1]:
        return -1

    left = 0
    right = len(nums) - 1
    while left + 1 < right:      # 统一都用 <
        mid = left + (right - left)//2
        if target > nums[mid]:    # 左边界> 右边界>=
            left = mid            # 永远不动,全文通用
        elif target < nums[mid]:
            right = mid           # 永远不动,全文通用
        else:
            return mid            # 等号可以合并到 < 或 > 也可以单独考虑

    if nums[right] == target:
        return right
    if nums[left] == target:
        return left

    return -1                     # 较小的left,较大的right

总结:

1.判断是返回left,还是返回right
     因为我们知道最后跳出while (left + 1< right)循环条件是left+ 1 == right。
     最后left 和right一定是卡在"边界值"的左右两边
     以数组{1, 2, 3, 3, 4,5}为例,
     如果需要查找第一个等于或者小于3的元素下标,我们比较的key值是3,则最后left和right需要满足以下条件:
     left——>2, right ——>3
     我们比较的key值是3,所以此时我们需要返回right 。

    所以,最后只需要判断left或right是否等于target即可。
2.判断出比较符号
     左边界附近都是>
     右边界附近都>=

举例说明:

1.lower_bound1, 则是返回的是被查序列中最后一个 < 查找值的指针

def lower_bound1(nums, target):
    if not nums or target < nums[0]:  # 只需要判断左边界
        return -1

    left = 0
    right = len(nums) - 1
    while left + 1 < right:             # 统一都用 <
        mid = left + (right - left) // 2
        if target > nums[mid]:          # 左边界> 
            left = mid                  # 不动
        else:
            right = mid                 # 不动

    if nums[right] < target:            # 当target > nums[-1]时
        return right

    return left   # 较小的left,较大的right

 2.lower_bound2, 则是返回的是被查序列中最后一个 <= 查找值的指针

def lower_bound2(nums, target):
    if not nums or target < nums[0]:  # 只需要判断左边界
        return -1

    left = 0
    right = len(nums) - 1
    while left + 1 < right:             # 统一都用 <
        mid = left + (right - left) // 2
        if target > nums[mid]:          # 左边界>
            left = mid                  # 不动
        else:
            right = mid                 # 不动

    if nums[left] == target:            # 当target == nums[0]时
        return left

    return right   # 较小的left,较大的right
    
 

3.upper_bound1, 则是返回的是被查序列中第一个 >= 查找值的指针

def upper_bound1(nums, target):
    if not nums or target > nums[-1]:  # 只需要判断右边界
        return -1

    left = 0
    right = len(nums) - 1
    while left + 1 < right:             # 统一都用 <
        mid = left + (right - left) // 2
        if target >= nums[mid]:         # 右边界>=
            left = mid                  # 不动
        else:
            right = mid                 # 不动

    if nums[right] == target:            # 当target == nums[-1]时
        return right

    return left   # 较小的left,较大的right

4.upper_bound2, 返回的是被查序列中最后一个 = 查找值的指针

def upper_bound2(nums, target):
    if not nums or target > nums[-1]:  # 只需要判断右边界
        return -1

    left = 0
    right = len(nums) - 1
    while left + 1 < right:             # 统一都用 <
        mid = left + (right - left) // 2
        if target >= nums[mid]:         # 右边界>=
            left = mid                  # 不动
        else:
            right = mid                 # 不动

    if nums[left] == target:
        return left
    if nums[right] == target:           # 当target == nums[-1]时
        return right

    return -1   # 较小的left,较大的right

5.upper_bound3,返回的是被查序列中第一个 > 查找值的指针

def upper_bound3(nums, target):
    if not nums or target > nums[-1]:  # 只需要判断右边界
        return -1

    left = 0
    right = len(nums) - 1
    while left + 1 < right:             # 统一都用 <
        mid = left + (right - left) // 2
        if target >= nums[mid]:         # 右边界>=
            left = mid                  # 不动
        else:
            right = mid                 # 不动

    if nums[right] == target:           # 当target == nums[-1]时
        return -1

    return right   # 较小的left,较大的right

递归版:

def recursive(arr, low, high, key):
    if low > high:
        return -1
    mid = (low + high) // 2
    if arr[mid] == key:
        return mid
    if arr[mid] < key:
        return recursive(arr, mid + 1, high, key)
    return recursive(arr, low, mid - 1, key)

下期内容:

其余练习题1:https://www.cnblogs.com/rnanprince/p/11743414.html

二分查找(倍增法):https://mp.csdn.net/postedit/102811021

其余练习题2:https://www.cnblogs.com/rnanprince/p/11761940.html

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值