尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

刷题复习(四)二分搜索

刷题复习(四)二分搜索
📅 发布时间:2026/6/19 0:50:04

代码框架

int binarySearch(int[] nums, int target) {int left = 0, right = ...;while(...) {int mid = left + (right - left) / 2;if (nums[mid] == target) {...} else if (nums[mid] < target) {left = ...} else if (nums[mid] > target) {right = ...}}return ...;
}

另外提前说明一下,计算 mid 时需要防止溢出,代码中 left + (right - left) / 2 就和 (left + right) / 2 的结果相同,但是有效防止了 left 和 right 太大,直接相加导致溢出的情况。

一、寻找一个数(基本的二分搜索)

class Solution {// 标准的二分搜索框架,搜索目标元素的索引,若不存在则返回 -1public int search(int[] nums, int target) {int left = 0;// 注意int right = nums.length - 1;while(left <= right) {int mid = left + (right - left) / 2;if(nums[mid] == target) {return mid;   } else if (nums[mid] < target) {// 注意left = mid + 1;} else if (nums[mid] > target) {// 注意right = mid - 1;}}return -1;}
}

核心思路: [left, right] 两端都闭的区间。这个区间其实就是每次进行搜索的区间。

如果 target 不存在,搜索左侧边界的二分搜索返回的索引是大于 target 的最小索引。

此算法有什么缺陷?

答:至此,你应该已经掌握了该算法的所有细节,以及这样处理的原因。但是,这个算法存在局限性。

比如说给你有序数组 nums = [1,2,2,2,3],target 为 2,此算法返回的索引是 2,没错。但是如果我想得到 target 的左侧边界,即索引 1,或者我想得到 target 的右侧边界,即索引 3,这样的话此算法是无法处理的。

这样的需求很常见,你也许会说,找到一个 target,然后向左或向右线性搜索不行吗?可以,但是不好,因为这样难以保证二分查找对数级的复杂度了。

二、寻找左侧边界的二分搜索

int left_bound(int[] nums, int target) {int left = 0;// 注意int right = nums.length;// 注意while (left < right) {int mid = left + (right - left) / 2;if (nums[mid] == target) {right = mid;} else if (nums[mid] < target) {left = mid + 1;} else if (nums[mid] > target) {// 注意right = mid;}}return left;
}

为什么是 left = mid + 1 和 right = mid?

为什么 left = mid + 1,right = mid ?和之前的算法不一样?

答:这个很好解释,因为我们的「搜索区间」是 [left, right) 左闭右开,所以当 nums[mid] 被检测之后,下一步应该去 mid 的左侧或者右侧区间搜索,即 [left, mid) 或 [mid + 1, right)。

为什么该算法能够搜索左侧边界?

答:关键在于对于 nums[mid] == target 这种情况的处理:

    if (nums[mid] == target)right = mid;

可见,找到 target 时不要立即返回,而是缩小「搜索区间」的上界 right,在区间 [left, mid) 中继续搜索,即不断向左收缩,达到锁定左侧边界的目的。

左闭右闭写法

int left_bound(int[] nums, int target) {int left = 0, right = nums.length - 1;// 搜索区间为 [left, right]while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] < target) {// 搜索区间变为 [mid+1, right]left = mid + 1;} else if (nums[mid] > target) {// 搜索区间变为 [left, mid-1]right = mid - 1;} else if (nums[mid] == target) {// 收缩右侧边界right = mid - 1;}}// 判断 target 是否存在于 nums 中// 如果越界,target 肯定不存在,返回 -1if (left < 0 || left >= nums.length) {return -1;}// 判断一下 nums[left] 是不是 targetreturn nums[left] == target ? left : -1;
}

三、寻找右侧边界的二分查找

类似寻找左侧边界的算法,这里也会提供两种写法,还是先写常见的左闭右开的写法,只有两处和搜索左侧边界不同:

int right_bound(int[] nums, int target) {int left = 0, right = nums.length;while (left < right) {int mid = left + (right - left) / 2;if (nums[mid] == target) {// 注意left = mid + 1;} else if (nums[mid] < target) {left = mid + 1;} else if (nums[mid] > target) {right = mid;}}// 注意return left - 1;
}

当 target 不存在时,right_bound 返回值的含义

直接说结论,和前面讲的 left_bound 相反:如果 target 不存在,搜索右侧边界的二分搜索返回的索引是小于 target 的最大索引。

int right_bound(int[] nums, int target) {int left = 0, right = nums.length - 1;while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] < target) {left = mid + 1;} else if (nums[mid] > target) {right = mid - 1;} else if (nums[mid] == target) {// 这里改成收缩左侧边界即可left = mid + 1;}}// 最后改成返回 left - 1if (left - 1 < 0 || left - 1 >= nums.length) {return -1;}return nums[left - 1] == target ? (left - 1) : -1;
}

875. 爱吃香蕉的珂珂 - 力扣(LeetCode)

珂珂喜欢吃香蕉。这里有 n 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 h 小时后回来。珂珂可以决定她吃香蕉的速度 k (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k 根。如果这堆香蕉少于 k 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。  珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。返回她可以在 h 小时内吃掉所有香蕉的最小速度 k(k 为整数)。示例 1:输入:piles = [3,6,7,11], h = 8
输出:4
示例 2:输入:piles = [30,11,23,4,20], h = 5
输出:30
示例 3:输入:piles = [30,11,23,4,20], h = 6
输出:23// 完整可运行版本
class Solution {public int minEatingSpeed(int[] piles, int h) {int left = 1;int right = 1_000_000_000;while (left <= right) {int mid = left + (right - left) / 2;if (f(piles, mid) == h) {// 搜索左侧边界,则需要收缩右侧边界right = mid - 1;} else if (f(piles, mid) < h) {// 需要让 f(x) 的返回值大一些right = mid - 1;} else if (f(piles, mid) > h) {// 需要让 f(x) 的返回值小一些left = mid + 1;}}return left;}long f(int[] piles, int x) {long hour = 0;for (int i = 0; i < piles.length; i++) {hour += piles[i] / x;if (piles[i] % x > 0) {hour++;}}return hour;}
}

难点是如何抽象成二分搜索

image-20250615172050965

还有坑点在int会出现数字越界的case,要用long

image-20250615173543906

1011. 在 D 天内送达包裹的能力 - 力扣(LeetCode)

传送带上的包裹必须在 days 天内从一个港口运送到另一个港口。传送带上的第 i 个包裹的重量为 weights[i]。每一天,我们都会按给出重量(weights)的顺序往传送带上装载包裹。我们装载的重量不会超过船的最大运载重量。返回能在 days 天内将传送带上的所有包裹送达的船的最低运载能力。示例 1:输入:weights = [1,2,3,4,5,6,7,8,9,10], days = 5
输出:15
解释:
船舶最低载重 15 就能够在 5 天内送达所有包裹,如下所示:
第 1 天:1, 2, 3, 4, 5
第 2 天:6, 7
第 3 天:8
第 4 天:9
第 5 天:10请注意,货物必须按照给定的顺序装运,因此使用载重能力为 14 的船舶并将包装分成 (2, 3, 4, 5), (1, 6, 7), (8), (9), (10) 是不允许的。 
class Solution {public int shipWithinDays(int[] weights, int days) {int left = 0;// 注意,right 是开区间,所以额外加一int right = 1;for (int w : weights) {left = Math.max(left, w);right += w;}while (left < right) {int mid = left + (right - left) / 2;int cap = timeByLoad(weights, mid);if (cap > days) {left = mid + 1;} else if (cap < days) {right = mid;} else {right = mid;}}return left;}public int timeByLoad(int[] weights, int load) {int days = 0;for (int i = 0; i < weights.length; ) {int cap = load;while (i < weights.length) {if (cap < weights[i])break;elsecap -= weights[i];i++;}days++;}return days;}
}

重点注意需要对left和right进行剪纸不然会判超时.

image-20250615182154070

相关新闻

  • 练习第一天学习的内容
  • 常见小错误 FREQUENTLY MADE MISTAKES IN OI
  • 详细介绍:Linux相关概念和易错知识点(44)(IP地址、子网和公网、NAPT、代理)

最新新闻

  • 嵌入式MCU电气特性与FLASH操作深度解析:从数据手册到稳定设计
  • 2026 郑州八大装修公司综合实力排行榜 - GrowthUME
  • 爱回收到店估价和到手价差多少?iPhone 15 Pro实测报告 - 新闻快传
  • 2026沈阳非急救转运救护车TOP5盘点|辽中同城、浑河跨桥、棋盘山山地、院区转诊首选康跃转运 - 吉修匠
  • 2026长沙防水补漏权威指南:卫生间/屋面/外墙/地下室正规施工+透明报价+避坑全攻略 - 苏易修缮
  • 爱回收靠谱吗?一个测评博主的深度复盘 - 新闻快传

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号