二分查找及常见变体

简介: 二分查找及常见变体

概述


二分查找作为经典的查找算法,思想比较简单,日常使用频繁。每次编写二分相关代码,经常会出现左右区间混乱,不知道如何划分区间等问题,造成做不出题目。


代码分析


  • 区间的左右开闭问题: [0, length - 1]
  • 循环边界: while left < right,这样可以保证最终返回值left == right,随便返回哪个都可以
  • 区间[left.. right]可以划分为两种情况:
  • 分为[left..mid][mid+1..right],分别对应right = midleft = mid + 1
  • 分为[left..mid-1][mid..right],分别对应right = mid-1left = mid。在这种情况下,需要将mid = left + (right - left) / 2修改为 mid = left + (right - left + 1) / 2,否则将出现死循环。


例如 nums = [1,2,3,5]target = 5,若不修改 mid 计算,便会出现死循环


常见二分变体


查找第一个等于给定值的元素


第一个等于,逻辑上发生在数组左边,因此收缩右边界。


def firstEquals(nums, target):
    left, right = 0, len(nums) - 1 
    while left < right: 
        mid = left + (right - left)//2 # 防止溢出, //表示整除
        if nums[mid] < target: 
            left = mid + 1 
        else:
            right = mid # 收缩右边界
    return left 
复制代码


查找最后一个等于给定值的元素


最后一个等于,逻辑上发生在数组右边,因此收缩左边界。


def lastEquals(nums, target): 
    left, right = 0, len(nums) - 1
    mid = left + (right - left + 1) // 2
    while left < right:
        if nums[mid] > target:
            right = mid - 1
        else :
            left = mid
    return left
复制代码


查找第一个大于等于给定值的元素


第一个大于等于,逻辑上发生在数组左边,因此收缩右边界。


def firstLessEquals(nums, target): 
    left, right = 0, len(nums) - 1
    mid = left + (right - left) // 2
    while left < right:
        if nums[mid] < target:
            left = mid + 1
        else :
            right = mid
    return left
复制代码


查找最后一个小于等于给定值的元素


最后一个小于等于,逻辑上发生在数组右边,因此收缩左边界。


def firstLessEquals(nums, target): 
    left, right = 0, len(nums) - 1
    mid = left + (right - left + 1) // 2
    while left < right:
        if nums[mid] > target:
            right = mid - 1
        else :
            left = mid
    return left
复制代码


总结



通过多个角度的学习,自己暂且总结一个自用结论,当查找或者插入为第一个(偏左侧)时,收缩右边界right = mid;当为最后一个(偏右侧)时,收缩左边界left = mid


往期精彩文章



后语


如果大家感觉此文对你有一些帮助,希望能点个赞,鼓励鼓励阿包,阿包会不断努力的。另外如果本文章有问题,或者对文章其中一部分不理解,都可以评论区回复我,我们来一起讨论,共同学习,一起进步!


相关文章
排列组合算法
排列组合算法
|
算法 搜索推荐
数据结构(2)时间复杂度——渐进时间复杂度、渐进上界、渐进下界
2.1.概述 算法的基本定义: 求解问题的一系列计算或者操作。 衡量算法性能的指标: 时间复杂性 空间复杂性
556 0
|
存储 算法 Java
Java数据结构与算法分析(二)稀疏数组
在介绍稀疏数组前我们先来引入一个需求,下面是一个五子棋的棋盘(15 * 15),玩到中途时想要保存离开,希望下次打开还可以继续玩。我们怎么实现呢?
72 0
|
算法 索引
LeetCode算法小抄--二分查找及其变体形式
LeetCode算法小抄--二分查找及其变体形式
|
存储 算法 Python
秒懂算法 | 子集树模型——0-1背包问题的回溯算法及动态规划改进
给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为W。一种物品要么全部装入背包,要么全部不装入背包,不允许部分装入。装入背包的物品的总重量不超过背包的容量。问应如何选择装入背包的物品,使得装入背包中的物品总价值最大?
520 0
秒懂算法 | 子集树模型——0-1背包问题的回溯算法及动态规划改进
|
算法 索引
【21天算法学习】顺序查找
【21天算法学习】顺序查找
65 0
|
算法 Java 索引
经典算法——顺序查找
经典算法——顺序查找
经典算法——顺序查找
|
算法 搜索推荐
【算法专题】秒懂如何运用二分查找算法
【算法专题】秒懂如何运用二分查找算法
【算法专题】秒懂如何运用二分查找算法
|
存储 算法 C#
【查找算法】二分查找(C# + 递归、非递归和变种形式)
本文主要介绍二分查找算法,通过图片解析每一次查找的情况。代码通过C#实现,分别有递归、非递归和变种三种形式。其中变种主要**解决数组出现重复数据**的问题。最后,我们还分析了二分查找的局限性。
【查找算法】二分查找(C# + 递归、非递归和变种形式)
|
机器学习/深度学习 算法
【计算理论】计算复杂性 ( 小 O 记号 | 严格渐进上界 | 分析算法的时间复杂度 )
【计算理论】计算复杂性 ( 小 O 记号 | 严格渐进上界 | 分析算法的时间复杂度 )
238 0