跳到主要内容

二分查找

本节目标

从搜索区间和循环不变量出发,掌握边界、局部有序与映射后的二分查找。

二分并不是“看到有序数组就套模板”。它的核心是:先明确答案仍可能出现的搜索区间,再借助单调、有序或局部趋势,每轮安全排除一半候选。

识别信号

  • 数据整体有序,要求查找一个值或它的插入位置;
  • 条件从某个位置开始持续成立,要求第一个或最后一个满足条件的位置;
  • 数组经过旋转、矩阵经过映射,但仍能判断一半区域不可能包含答案;
  • 相邻元素的升降趋势能说明某一侧必然保留候选。

问题模型

精确查找使用左闭右闭区间 [left, right]:循环开始时,若目标存在,它一定在这个区间中。比较 nums[mid] 后,要么直接返回,要么排除一个已知不含目标的部分。

边界查找改为半开区间 [left, right)。它不问“是否找到”,而问“第一个满足条件的位置在哪里”;即使目标不存在,返回值也仍是合法插入位置。

通用模板

左闭右闭的精确查找:

left = 0, right = n - 1
while left <= right:
mid = left + (right - left) / 2
比较 nums[mid] 与 target
保留仍可能包含 target 的半边

第一个满足条件的位置:

left = 0, right = n
while left < right:
mid = left + (right - left) / 2
if 条件(mid) 成立:
right = mid
else:
left = mid + 1
return left

模板变体

  • 查首尾位置:分别取第一个 >= target 与第一个 > target
  • 旋转数组:先识别哪一半有序,再检查目标是否落在该值域;
  • 二维矩阵:把一维下标用除法和取模还原为行、列;
  • 峰值:根据中点和右邻元素的升降,保留必然存在峰值的一侧。

这些变化改变的是“如何证明可以排除”,而不是机械地背另一套代码。

母题序列

必学顺序完成:

  1. 二分查找 必学
  2. 在排序数组中查找元素的第一个和最后一个位置 必学
  3. 搜索插入位置 必学
  4. 搜索旋转排序数组 必学
  5. 寻找旋转排序数组中的最小值 必学
  6. 搜索二维矩阵 必学
  7. 寻找峰值 必学

常见误区

  • 区间语义混用:初始化、循环条件和更新规则必须是同一套区间约定。
  • target + 1 寻找右边界:整数最大值会溢出,应直接使用 nums[mid] > target
  • 未验证排除规则:旋转数组和峰值题都不能只因“看起来像二分”就删除一侧。
  • 忘记空输入:矩阵映射前先确认矩阵和首行都非空。

迁移方向

下一步可进入二分答案:把搜索对象从数组下标改成速度、容量或最大代价。无论对象是什么,先写出不变量和单调性,再决定二分边界。