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

二分查找介绍

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

二分查找算法

需求 :在有序数组 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 为二分的上界。
  • 空间复杂度:,过程中仅用到常数个变量。
相关推荐
java排坑日记1 小时前
poi-tl+kkviewfile实现生成pdf业务报告
java·pdf·word
V+zmm101342 小时前
校园约拍微信小程序设计与实现ssm+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm
猿来入此小猿2 小时前
基于SpringBoot小说平台系统功能实现四
java·spring boot·毕业设计·毕业源码·在线小说阅读·在线小说平台·免费学习:猿来入此
狄加山6752 小时前
数据结构(红黑树)
数据结构
狄加山6752 小时前
数据结构(查找算法)
数据结构·数据库·算法
陌然。。2 小时前
【701. 二叉搜索树中的插入操作 中等】
数据结构·c++·算法·leetcode·深度优先
Ritsu栗子2 小时前
代码随想录算法训练营day25
c++·算法
是十一月末3 小时前
机器学习之过采样和下采样调整不均衡样本的逻辑回归模型
人工智能·python·算法·机器学习·逻辑回归
生信碱移3 小时前
万字长文:机器学习的数学基础(易读)
大数据·人工智能·深度学习·线性代数·算法·数学建模·数据分析