当前位置: 首页 > news >正文

二分查找模板:基础二分与进阶二分

二分查找模板:基础二分与进阶二分

本人在学习到 @灵茶山艾府 的二分查找专题时,收获颇多,故借助大模型记录一些学习心得。
根据目标不同,二分查找可以分为 基础二分(情况1:查找任意一个目标值)和 进阶二分(查找第一个目标值/最后一个目标值)。二分查找的目标是在一个区间查找目标值,故可将区间分为 均闭区间 [left, right]、均开区间 (left, right)、左闭右开 [left, right)、左开右闭 (left, right] 四种,常用的是 均闭区间。几种类型的区间仅在左右边界的收缩以及循环条件的编码方面有所差异。下面以均闭区间为例总结模板。

均闭区间在进阶二分问题的最终形态为 left > right ,此时left指向最后一个目标值。


1. 基础二分(查找任意一个目标值)

目标:找到数组中是否存在 target,返回任意一个索引。

模板

int binarySearch(vector<int>& nums, int target) {int left = 0, right = nums.size() - 1;while (left <= right) {             // 区间 [left, right]int mid = (left + right) / 2;if (nums[mid] == target) return mid;  // 找到直接返回else if (nums[mid] < target) left = mid + 1;  // 缩小到右区间else right = mid - 1;                       // 缩小到左区间}return -1; // 未找到
}
  • 条件分支包含 =,找到直接返回。

2. 进阶二分(情况1):查找第一个目标值(左边界)

目标:找到 target 在数组中第一次出现的位置。

模板

@灵茶山艾府 的Leetcode T34题解

// lower_bound 返回最小的满足 nums[i] >= target 的下标 i
// 如果数组为空,或者所有数都 < target,则返回 nums.size()
// 要求 nums 是非递减的,即 nums[i] <= nums[i + 1]
int lower_bound(vector<int>& nums, int target) {int left = 0, right = (int) nums.size() - 1; // 闭区间 [left, right]while (left <= right) { // 区间不为空// 循环不变量:// nums[left-1] < target// nums[right+1] >= targetint mid = left + (right - left) / 2;  // 这种写法的目的是防止 (left + right) / 2 的分子溢出if (nums[mid] >= target) {right = mid - 1; // 范围缩小到 [left, mid-1]} else {left = mid + 1; // 范围缩小到 [mid+1, right]}}// 循环结束后 left = right+1// 此时 nums[left-1] < target 而 nums[left] = nums[right+1] >= target// 所以 left 就是第一个 >= target 的元素下标return left;
}
  • = 并入 >= 分支,使搜索继续收缩到最左边。

3. 进阶二分(情况2):查找最后一个目标值(右边界)

目标:找到 target 在数组中最后一次出现的位置。

模板

// upper_bound 返回最大的满足 nums[i] <= target 的下标 i
// 如果数组为空,或者所有数都 > target,则返回 -1
// 要求 nums 是非递减的,即 nums[i] <= nums[i + 1]
int upper_bound(vector<int>& nums, int target) {int left = 0, right = (int) nums.size() - 1; // 闭区间 [left, right]while (left <= right) { // 区间不为空// 循环不变量:// nums[left-1] <= target// nums[right+1] > targetint mid = left + (right - left) / 2;   // 这种写法的目的是防止 (left + right) / 2 的分子溢出if (nums[mid] <= target) {left = mid + 1;   // 范围缩小到 [mid+1, right]} else {right = mid - 1;  // 范围缩小到 [left, mid-1]}}// 循环结束后 right = left-1// 此时 nums[right] <= target 且 nums[left] = nums[right+1] > target// 所以 right 就是最后一个 <= target 的元素下标return right;
}
  • = 并入 <= 分支,使搜索继续收缩到最右边。

4. 总结

  • 基础二分(任意值):= 时立即返回。
  • 进阶二分(左边界)=> 合并,收缩右边界。
  • 进阶二分(右边界)=< 合并,收缩左边界。
  • 区间选择:不同区间定义(闭/开)影响循环条件和更新方式,模板需统一风格。建议使用均开/均闭区间的模板。
http://www.hskmm.com/?act=detail&tid=25663

相关文章:

  • 【设计模式-4.5】行为型——迭代器模式 - 教程
  • 循环结构
  • SP6950 CTOI10D3 - A HUGE TOWER 题解
  • 浅谈并查集
  • 16_AiAgentMCP简单教程
  • 17_AiAgentMCP实现技术选型
  • JVM_XMS 和 java_opts哪种写法对?如何在JVM中设置JVM_XMS和java_opts?
  • POLIR-Society-Philosophy-mind: 思想/精神
  • 鸿蒙编译ffmpeg库 - 详解
  • 知道却做不到
  • 题解:loj154 集合划分计数
  • 为什么 Java 中打印Object类型的变量无需强转,而从Object类型的数组中取元素却要强转?
  • WinReanimator恶意软件清除指南:详细步骤与工具使用
  • 251006
  • 2025国庆Day5
  • 字节跳动开源图标库:2000+图标一键换肤的魔法 - 教程
  • 换根DP学习笔记
  • 自动化数据操作平台获3000万美元融资
  • 模块
  • 实用指南:【相机基础知识与物体检测】更新中
  • AtCoder Beginner Contest 422 游记(VP)
  • 详细介绍:无人机光纤FC接口模块技术分析
  • 2025 --【J+S 二十连测】-- 第十三套 总结
  • 文件提供的基本操作
  • 深入解析:MySQL(50)如何使用UNSIGNED属性?
  • 迈向人机价值共生文明:AI元人文范式下的演化架构与协同治理
  • 10.6
  • 文件存储空间管理
  • 详细介绍:关于ios点击分享自动复制到粘贴板的问题
  • 新一代数据平台替代传统大数据技术栈