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

二分查找介绍

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

二分查找算法

需求 :在有序数组 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 分钟前
class 031 位运算的骚操作
java·算法·位运算
2401_8581205314 分钟前
古典舞在线交流平台:SpringBoot设计与实现详解
java·spring boot·后端
大白飞飞22 分钟前
IDEA创建、导入、删除maven项目
java·maven·intellij-idea
赐你岁月如歌26 分钟前
如何使用ssm实现基于web的网站的设计与实现+vue
java·后端·ssm
时清云27 分钟前
【算法】合并两个有序链表
前端·算法·面试
轩辰~44 分钟前
磁盘存储链式结构——B树与B+树
数据结构·b树·算法
2401_857297911 小时前
秋招内推2025-招联金融
java·前端·算法·金融·求职招聘
一 乐1 小时前
考研论坛平台|考研论坛小程序系统|基于java和微信小程序的考研论坛平台小程序设计与实现(源码+数据库+文档)
java·数据库·学习·考研·微信·小程序·源码
一 乐1 小时前
租拼车平台|小区租拼车管理|基于java的小区租拼车管理信息系统小程序设计与实现(源码+数据库+文档)
java·数据库·vue.js·微信·notepad++·拼车
通信仿真实验室1 小时前
MATLAB使用眼图分析QPSK通信系统接收端匹配滤波后的信号
开发语言·算法·matlab