【数据结构算法】简单的二分查找,大有文章

二分查找介绍

二分查找算法是一种用于在有序数组或列表中查找特定元素的方法。它通过反复将搜索空间一分为二,直到找到目标元素或确定其不存在。

二分查找算法

需求 :在有序数组 a 内,查找值 target

  • 如果找到返回索引
  • 如果找不到返回 -1
java 复制代码
public static int binarySearch(int[] a, int target) {
    int i = 0, j = a.length - 1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {            // 在左边
            j = m - 1;
        } else if (a[m] < target) {        // 在右边
            i = m + 1;
        } else {
            return m;
        }
    }
    return -1;
}
  • binarySearch 方法接受一个数组 a 和目标值 target 作为参数。它初始化两个指针 i 和 j ,分别指向数组的起始和结束索引。
  • 算法进入一个 while 循环,在循环中,直到 i 指针大于 j 指针才会停止。在每次迭代中,它计算中间索引 m ,并将该索引处的元素与目标值进行比较。
  • 如果不加 i==j行不行? 不行,因为这意味着 i,j 指向的元素会漏过比较
  • 计算中间所以这里建议使用无符号右移>>>, 向右边移动一位,相当于除以2。如果使用(i + j)/2 ,i和j两个数很大相加,会超过int的范围,导致中间值变为负数。
  • 如果 m 处的元素等于目标值,方法返回索引 m ,表示找到了目标元素。如果 m 处的元素小于目标值,则将搜索范围缩小为数组的右半部分,更新 i 指针。相反,如果 m 处的元素大于目标值,则将搜索范围缩小为数组的左半部分,更新 j 指针。
  • 如果 while 循环完成而未找到目标元素,则方法返回 -1,表示在数组中未找到该元素。

二分查找时间复杂度

  • 黑色横线 O(1),常量时间,意味着算法时间并不随数据规模而变化
  • 绿色 O(log(n)),对数时间
  • 蓝色 O(n),线性时间,算法时间与数据规模成正比
  • 橙色 O(n*log(n)),拟线性时间
  • 红色 O(n^2) 平方时间
  • 黑色朝上 O(2^n) 指数时间

二分查找是一种高效的算法,其时间复杂度为 O(log n),其中 n 是数组中元素的个数。

时间复杂度

  • 最坏情况:O(log n)
  • 最好情况:如果待查找元素恰好在数组中央,只需要循环一次 O(1)

空间复杂度

  • 需要常数个指针 i,j,m,因此额外占用的空间是 O(1)

二分查找进阶

前面的需求都是找到一个满足条件的数据,现在需要返回相同元素最左侧的元素,比如[1, 4, 4, 5, 6],返回第一个4的索引位置,该如何实现呢?

java 复制代码
public static int binarySearchLeftmost1(int[] a, int target) {
    int i = 0, j = a.length - 1;
    int candidate = -1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {
            j = m - 1;
        } else if (a[m] < target) {
            i = m + 1;
        } else {
            candidate = m; // 记录候选位置
            j = m - 1;     // 继续向左
        }
    }
    return candidate;
}

同样返回相同元素最右边的索引就不赘述了。

二分查找活学活用

题目:LC2594. 修车的最少时间

最近leetcode上推荐了一道题目,挺有意思的,大家可以思考下利用上面的知识如何解决。

思路

  • 如果时间为t, 根据题目能力值为 r 的机械工可以在 r * n2 分钟内修好 n 辆车,可得每个机械工修理的汽车数量是Math.sqrt(t/r)
  • 假设最小时间10分钟,如果满足Math.sqrt(10/4) + Math.sqrt(10/2) +...+ Math.sqrt(10/1)>cars数量,意味着10分钟内修理10辆车绰绰有余,那么我尝试9分钟,知道找到最小的时间。
  • 这种存在单调性,我们可以使用二分法方法,左边从0或者1开始,右边从某一台花费的时间ranks[0]*cars*cars作为上界。

代码

java 复制代码
public long repairCars(int[] ranks, int cars) {
    // high必须要加1L,不然两个很大cars相乘int存不下
    long low = 0, high = 1L * ranks[0] * cars * cars;
    while (low <= high) {
        long mid = (low + high) >>> 1;
        long fixedCars = 0;
        for (int rank : ranks) {
            fixedCars += (long)Math.sqrt(mid / rank);
        }
        // 时间满足条件
        if(fixedCars >= cars) {
            high = mid - 1;
        } else {
            low = mid + 1;
        }
    }
    return low;
}
  • 注意这里上界限必须乘以1L,否则cars很大时int无法存储,出现负数的情况。
  • 时间复杂度:其中 n 为ranks 的长度,L 为二分的上界。
  • 空间复杂度:,过程中仅用到常数个变量。
相关推荐
惜.己11 分钟前
Jmeter中的配置原件(四)
java·前端·功能测试·jmeter·1024程序员节
用户405478783748235 分钟前
深度学习笔记 - 使用YOLOv5中的c3模块进行天气识别
算法
yava_free35 分钟前
JVM这个工具的使用方法
java·jvm
shinelord明39 分钟前
【再谈设计模式】建造者模式~对象构建的指挥家
开发语言·数据结构·设计模式
十七算法实验室44 分钟前
Matlab实现麻雀优化算法优化随机森林算法模型 (SSA-RF)(附源码)
算法·决策树·随机森林·机器学习·支持向量机·matlab·启发式算法
黑不拉几的小白兔1 小时前
PTA部分题目C++重练
开发语言·c++·算法
迷迭所归处1 小时前
动态规划 —— dp 问题-买卖股票的最佳时机IV
算法·动态规划
不会编程的懒洋洋1 小时前
Spring Cloud Eureka 服务注册与发现
java·笔记·后端·学习·spring·spring cloud·eureka
赖龙1 小时前
java程序打包及执行 jar命令及运行jar文件
java·pycharm·jar
U12Euphoria1 小时前
java的runnable jar采用exe和.bat两种方式解决jre环境的问题
java·pycharm·jar