Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >二分搜索只能用来查找元素吗?

二分搜索只能用来查找元素吗?

作者头像
labuladong
发布于 2021-09-23 02:10:11
发布于 2021-09-23 02:10:11
38300
代码可运行
举报
运行总次数:0
代码可运行

预计阅读时间:6 分钟

二分查找到底能运用在哪里?

最常见的就是教科书上的例子,在有序数组中搜索给定的某个目标值的索引。再推广一点,如果目标值存在重复,修改版的二分查找可以返回目标值的左侧边界索引或者右侧边界索引。

PS:以上提到的三种二分查找算法形式在前文 二分查找算法详解 有代码详解,如果没看过强烈建议看看。

抛开有序数组这个枯燥的数据结构,二分查找如何运用到实际的算法问题中呢?当搜索空间有序的时候,就可以通过二分搜索「剪枝」,大幅提升效率。

说起来玄乎得很,本文用「Koko 吃香蕉」和「货物运输」的问题来举个例子。

一、Koko 吃香蕉

也就是说,Koko 每小时最多吃一堆香蕉,如果吃不下的话留到下一小时再吃;如果吃完了这一堆还有胃口,也只会等到下一小时才会吃下一堆。在这个条件下,让我们确定 Koko 吃香蕉的最小速度(根/小时)。

如果直接给你这个情景,你能想到哪里能用到二分查找算法吗?如果没有见过类似的问题,恐怕是很难把这个问题和二分查找联系起来的。

那么我们先抛开二分查找技巧,想想如何暴力解决这个问题呢?

首先,算法要求的是「H小时内吃完香蕉的最小速度」,我们不妨称为speed请问speed最大可能为多少,最少可能为多少呢?

显然最少为 1,最大为max(piles),因为一小时最多只能吃一堆香蕉。那么暴力解法就很简单了,只要从 1 开始穷举到max(piles),一旦发现发现某个值可以在H小时内吃完所有香蕉,这个值就是最小速度:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int minEatingSpeed(int[] piles, int H) {
    // piles 数组的最大值
    int max = getMax(piles);
    for (int speed = 1; speed < max; speed++) {
        // 以 speed 是否能在 H 小时内吃完香蕉
        if (canFinish(piles, speed, H))
            return speed;
    }
    return max;
}

注意这个 for 循环,就是在连续的空间线性搜索,这就是二分查找可以发挥作用的标志。

由于我们要求的是最小速度,所以可以用一个搜索左侧边界的二分查找来代替线性搜索,提升效率:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int minEatingSpeed(int[] piles, int H) {
    // 套用搜索左侧边界的算法框架
    int left = 1, right = getMax(piles) + 1;
    while (left < right) {
        // 防止溢出
        int mid = left + (right - left) / 2;
        if (canFinish(piles, mid, H)) {
            right = mid;
        } else {
            left = mid + 1;
        }
    }
    return left;
}

PS:如果对于这个二分查找算法的细节问题有疑问,建议看下前文 二分查找算法详解 搜索左侧边界的算法模板,这里不展开了。

剩下的辅助函数也很简单,可以一步步拆解实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 时间复杂度 O(N)
boolean canFinish(int[] piles, int speed, int H) {
    int time = 0;
    for (int n : piles) {
        time += timeOf(n, speed);
    }
    return time <= H;
}

int timeOf(int n, int speed) {
    return (n / speed) + ((n % speed > 0) ? 1 : 0);
}

int getMax(int[] piles) {
    int max = 0;
    for (int n : piles)
        max = Math.max(n, max);
    return max;
}

至此,借助二分查找技巧,算法的时间复杂度为 O(NlogN)。

二、包裹运输问题

类似的,再看一道运输问题:

要在D天内运输完所有货物,货物不可分割,如何确定运输的最小载重呢(下文称为cap)?

其实本质上和 Koko 吃香蕉的问题一样的,首先确定cap的最小值和最大值分别为max(weights)sum(weights)

类似刚才的问题,我们要求最小载重,可以用 for 循环从小到大遍历,那么就可以用搜索左侧边界的二分查找算法优化线性搜索:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 寻找左侧边界的二分查找
int shipWithinDays(int[] weights, int D) {
    // 载重可能的最小值
    int left = getMax(weights);
    // 载重可能的最大值 + 1
    int right = getSum(weights) + 1;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (canFinish(weights, D, mid)) {
            right = mid;
        } else {
            left = mid + 1;
        }
    }
    return left;
}

// 如果载重为 cap,是否能在 D 天内运完货物?
boolean canFinish(int[] w, int D, int cap) {
    int i = 0;
    for (int day = 0; day < D; day++) {
        int maxCap = cap;
        while ((maxCap -= w[i]) >= 0) {
            i++;
            if (i == w.length)
                return true;
        }
    }
    return false;
}

通过这两个例子,你是否明白了二分查找在实际问题中的应用呢?

首先思考使用 for 循环暴力解决问题,观察代码是否如下形式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for (int i = 0; i < n; i++)
    if (isOK(i))
        return answer;

如果是,那么就可以使用二分搜索优化搜索空间:如果要求最小值就是搜索左侧边界的二分,如果要求最大值就用搜索右侧边界的二分。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 labuladong 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
我写了一个套路,助你随心所欲运用二分搜索
读完本文,可以去力扣解决如下题目: 875.爱吃香蕉的珂珂(Medium) 1011.在D天内送达包裹的能力(Medium)
labuladong
2021/09/23
1.1K0
漫画:二分解题模板(第一讲)- 修订版
今天还是小浩算法“365刷题计划”第66天。昨天也是第66天,为什么?因为昨天我的内容忘记标识原创,马上就被人抄袭到了自己的博客,我很不爽!当然,经过投诉,对方已经删文。所以为了防止再次抄袭,我决定重新发布一下昨天的文章。考虑到本文有朋友已经学习过了,所以我在原有的基础上进行了加强,并且答疑了昨天私下有人问我的几个问题,不妨看一看!暂定后续要讲解的几个topic为:二分法(以常考题目为主)、回溯法(大部分是中等以上难度题型)、分治法(以思想掌握为主)、动态规划(以2维DP为主)、其他。希望大家可以长期支持!一起学习,共同进步。
程序员小浩
2020/03/30
5170
漫画:二分解题模板(第一讲)- 修订版
【python刷题】二分查找
当数组中存在重复的元素的时候,我们要返回左右边界的时候,当查找到该元素时,我们不能返回True或者Fasle,而是要不断的缩小边界。
西西嘛呦
2021/02/05
6450
【python刷题】二分查找
算法篇:二分查找基础篇
https://leetcode-cn.com/problems/binary-search/
灰子学技术
2020/08/28
4570
漫画:二分法系列篇(第一讲)
不知道为什么叫做爱吃香蕉的阿珂,难道不应该是爱吃香蕉的猴子么...或者爱吃队友的露娜么?
程序员小浩
2020/03/30
5260
漫画:二分法系列篇(第一讲)
LeetCode 875. 爱吃香蕉的珂珂(二分查找)
珂珂喜欢吃香蕉。这里有 N 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 H 小时后回来。
Michael阿明
2020/07/13
4690
二分查找算法如何运用?我和快手面试官进行了深入探讨…
经常有读者问我,读了之前的爆文 二分查找框架详解 之后,二分查找的算法他写的很溜了,但仅仅局限于在数组中搜索元素,不知道底怎么在算法题里面运用二分查找技巧来优化效率。
labuladong
2021/09/23
4050
Python|二分查找算法解决包裹最低运载问题
传送带上的包裹必须在 D 天内从一个港口运送到另一个港口。传送带上的第i个包裹的重量为 weights[i]。每一天,都会按给出重量的顺序往传送带上装载包裹。装载的重量不会超过船的最大运载重量。返回能在 D 天内将传送带上的所有包裹送达的船的最低运载能力。
算法与编程之美
2020/05/16
7120
算法学习笔记-二分法
leetcode875爱吃香蕉的珂珂https://leetcode-cn.com/problems/koko-eating-bananas/
买唯送忧
2021/05/09
4370
二分查找学习笔记
二分查找也称折半查找,它是一种效率较高的查找方法。二分查找,思路很简单,细节是魔鬼。
EmoryHuang
2022/10/28
2670
二分查找学习笔记
初识算法 · 二分查找(1)
本文呢,我们从滑动窗口窗口算法移步到了二分查找算法,我们简单了解一下二分查找算法,二分查找算法是一个十分恶心,十分注重细节,但是同时也是十分简单的一个算法,有人好奇,注重细节和简单怎么能挂的上关系呢?这是因为二分查找对于边界的处理是尤其要小心的,所以对于二分查找来说,将边界处理好了,自然就简单多了,相当于套了一个模板。那么本文呢,通过两个题目,简单介绍一下二分查找算法。
_lazy
2024/10/18
1460
初识算法 · 二分查找(1)
leetcode刷题(86)——739.二分查找
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
老马的编程之旅
2022/06/22
2410
Kafka竟然也用二分搜索算法查找索引!
难得的是,Kafka的索引组件中应用了二分查找算法,而且社区还针对Kafka自身的特点对其进行了改良。
JavaEdge
2021/02/23
7030
Kafka竟然也用二分搜索算法查找索引!
Java算法探秘:二分查找详解
当你需要在一个有序数组中查找特定元素时,二分查找是一种高效的算法。它的时间复杂度为 O(log n),相较于线性查找的 O(n),二分查找可以显著提高搜索效率。本文将详细解释什么是二分查找,以及如何在 Java 中实现它。
修己xj
2023/09/12
8960
Java算法探秘:二分查找详解
备战蓝桥杯————二分搜索(一)
1. 循环条件:确保在搜索范围内进行,即left <= right。 2. 中间位置的计算:使用left + (right - left) / 2而不是(left + right) / 2来避免整数溢出。 3. 边界更新:根据中间值与目标值的比较结果,更新左边界或右边界。 4. 返回值:如果找到目标值,返回其索引;如果未找到,返回一个特定的值(如-1)表示未找到。
小小程序员
2024/03/07
1770
备战蓝桥杯————二分搜索(一)
二分查找算法,数组有序不是必要条件!
先来一段维基百科概念。“二分查找算法,也称折半搜索算法,是一种在有序数组中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。”
用户8639654
2021/07/23
1.5K0
精确与高效:二分查找的完整指南
二分查找是一种高效的搜索算法,以其简单优雅的实现和出色的性能被广泛应用于计算机科学和工程领域。从理论到实践,这一算法始终是理解数据结构与算法设计的基石。在本文中,我们将深入剖析二分查找的原理、实现和优化,帮助您掌握其核心思想与实际应用。
suye
2024/12/21
5210
二分查找算法详解
有一天阿东到图书馆借了 N 本书,出图书馆的时候,警报响了,于是保安把阿东拦下,要检查一下哪本书没有登记出借。阿东正准备把每一本书在报警器下过一下,以找出引发警报的书,但是保安露出不屑的眼神:你连二分查找都不会吗?于是保安把书分成两堆,让第一堆过一下报警器,报警器响;于是再把这堆书分成两堆…… 最终,检测了 log2N 次之后,保安成功的找到了那本引起警报的书,露出了得意和嘲讽的笑容。于是阿东背着剩下的书走了。
五分钟学算法
2019/06/18
1.1K0
二分查找算法详解
【优选算法篇】寻找隐藏的宝藏:用二分查找打开算法世界的大门(上篇)
二分查找(Binary Search)是一种经典的算法,广泛应用于计算机科学中,尤其在处理有序数据时。其重要性体现在以下几个方面:
熬夜学编程的小王
2024/12/24
2150
【优选算法篇】寻找隐藏的宝藏:用二分查找打开算法世界的大门(上篇)
Leetcode | 第4节:二分查找,归并排序
上一节我们说完了链表的一些高频题。那么这一节,我们会介绍一些二分查找和排序相关的题目。二分和排序本身不是很困难,但是还是有一些难题需要一些技巧才能解决(倒也不是完全毫无头绪的那种),所以这一篇文章,我们除了基本内容外,也会花一些时间介绍一下技巧性的内容。
学弱猹
2021/08/10
5730
Leetcode | 第4节:二分查找,归并排序
相关推荐
我写了一个套路,助你随心所欲运用二分搜索
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档