# 二分查找的实际运用

GitHub

![](https://labuladong.github.io/algo/images/souyisou1.png) **通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 已更新到 V2.0;[第 13 期刷题打卡](https://mp.weixin.qq.com/s/eUG2OOzY3k_ZTz-CFvtv5Q) 最后一天报名!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。** 读完本文,你不仅学会了算法套路,还可以顺便解决如下题目: | LeetCode | 力扣 | 难度 | | :----: | :----: | :----: | | [1011. Capacity To Ship Packages Within D Days](https://leetcode.com/problems/capacity-to-ship-packages-within-d-days/) | [1011. 在 D 天内送达包裹的能力](https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/) | 🟠 | [410. Split Array Largest Sum](https://leetcode.com/problems/split-array-largest-sum/) | [410. 分割数组的最大值](https://leetcode.cn/problems/split-array-largest-sum/) | 🔴 | [875. Koko Eating Bananas](https://leetcode.com/problems/koko-eating-bananas/) | [875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) | 🟠 | - | [剑指 Offer II 073. 狒狒吃香蕉](https://leetcode.cn/problems/nZZqjQ/) | 🟠 **-----------** 我们前文 [我写了首诗,把二分搜索变成了默写题](https://labuladong.github.io/article/fname.html?fname=二分查找详解) 详细介绍了二分搜索的细节问题,探讨了「搜索一个元素」,「搜索左侧边界」,「搜索右侧边界」这三个情况,教你如何写出正确无 bug 的二分搜索算法。 **但是前文总结的二分搜索代码框架仅仅局限于「在有序数组中搜索指定元素」这个基本场景,具体的算法问题没有这么直接,可能你都很难看出这个问题能够用到二分搜索**。 所以本文就来总结一套二分搜索算法运用的框架套路,帮你在遇到二分搜索算法相关的实际问题时,能够有条理地思考分析,步步为营,写出答案。 ### 原始的二分搜索代码 二分搜索的原型就是在「**有序数组**」中搜索一个元素 `target`,返回该元素对应的索引。 如果该元素不存在,那可以返回一个什么特殊值,这种细节问题只要微调算法实现就可实现。 还有一个重要的问题,如果「**有序数组**」中存在多个 `target` 元素,那么这些元素肯定挨在一起,这里就涉及到算法应该返回最左侧的那个 `target` 元素的索引还是最右侧的那个 `target` 元素的索引,也就是所谓的「搜索左侧边界」和「搜索右侧边界」,这个也可以通过微调算法的代码来实现。 **我们前文 [我写了首诗,把二分搜索变成了默写题](https://labuladong.github.io/article/fname.html?fname=二分查找详解) 详细探讨了上述问题,对这块还不清楚的读者建议复习前文**,已经搞清楚基本二分搜索算法的读者可以继续看下去。 **在具体的算法问题中,常用到的是「搜索左侧边界」和「搜索右侧边界」这两种场景**,很少有让你单独「搜索一个元素」。 因为算法题一般都让你求最值,比如让你求吃香蕉的「最小速度」,让你求轮船的「最低运载能力」,求最值的过程,必然是搜索一个边界的过程,所以后面我们就详细分析一下这两种搜索边界的二分算法代码。 「搜索左侧边界」的二分搜索算法的具体代码实现如下: ```java // 搜索左侧边界 int left_bound(int[] nums, int target) { if (nums.length == 0) return -1; int left = 0, right = nums.length; while (left < right) { int mid = left + (right - left) / 2; if (nums[mid] == target) { // 当找到 target 时,收缩右侧边界 right = mid; } else if (nums[mid] < target) { left = mid + 1; } else if (nums[mid] > target) { right = mid; } } return left; } ``` 假设输入的数组 `nums = [1,2,3,3,3,5,7]`,想搜索的元素 `target = 3`,那么算法就会返回索引 2。 如果画一个图,就是这样: ![](https://labuladong.github.io/algo/images/二分运用/1.jpeg) 「搜索右侧边界」的二分搜索算法的具体代码实现如下: ```java // 搜索右侧边界 int right_bound(int[] nums, int target) { if (nums.length == 0) return -1; int left = 0, right = nums.length; while (left < right) { int mid = left + (right - left) / 2; if (nums[mid] == target) { // 当找到 target 时,收缩左侧边界 left = mid + 1; } else if (nums[mid] < target) { left = mid + 1; } else if (nums[mid] > target) { right = mid; } } return left - 1; } ``` 输入同上,那么算法就会返回索引 4,如果画一个图,就是这样: ![](https://labuladong.github.io/algo/images/二分运用/2.jpeg) 好,上述内容都属于复习,我想读到这里的读者应该都能理解。记住上述的图像,所有能够抽象出上述图像的问题,都可以使用二分搜索解决。
引用本文的文章 - [丑数系列算法详解](https://labuladong.github.io/article/fname.html?fname=丑数) - [二分搜索怎么用?我和快手面试官进行了深度探讨](https://labuladong.github.io/article/fname.html?fname=二分分割子数组) - [我写了首诗,把二分搜索算法变成了默写题](https://labuladong.github.io/article/fname.html?fname=二分查找详解) - [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得) - [用算法打败算法 ](https://labuladong.github.io/article/fname.html?fname=PDF中的算法) - [经典动态规划:高楼扔鸡蛋](https://labuladong.github.io/article/fname.html?fname=高楼扔鸡蛋问题) - [讲两道常考的阶乘算法题](https://labuladong.github.io/article/fname.html?fname=阶乘题目)


引用本文的题目 安装 [我的 Chrome 刷题插件](https://mp.weixin.qq.com/s/X-fE9sR4BLi6T9pn7xP4pg) 点开下列题目可直接查看解题思路: | LeetCode | 力扣 | | :----: | :----: | | [1201. Ugly Number III](https://leetcode.com/problems/ugly-number-iii/?show=1) | [1201. 丑数 III](https://leetcode.cn/problems/ugly-number-iii/?show=1) | | - | [剑指 Offer II 073. 狒狒吃香蕉](https://leetcode.cn/problems/nZZqjQ/?show=1) |
**_____________** 应合作方要求,本文不便在此发布,请扫码关注回复关键词「二分」或 [点这里](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_627cce2de4b01a4851fe0ed1/1) 查看: ![](https://labuladong.github.io/algo/images/qrcode.jpg)