第6章|二分、堆与优先队列
Unit 02 · LeetCode #35
没有命中目标,
不代表二分没有找到答案。
插入位置是“第一个不小于target的位置”。目标不存在时,左右边界仍会收敛到唯一合法缝隙;目标存在时,这个边界恰好就是目标下标。
题目要求
给定一个按升序排列且元素互不相同的整数数组 nums 和目标值 target。若目标存在,返回其下标;否则返回目标按顺序插入数组时的位置。
要求算法时间复杂度为 O(log n)。
约束
1 ≤ nums.length ≤ 10⁴;-10⁴ ≤ nums[i], target ≤ 10⁴;nums严格递增。
官方示例
输出:2
输出:1
输出:4
本页主方法
寻找第一个满足 nums[i] ≥ target 的位置。使用半开候选区间 [left,right),其中 right 可等于 len(nums)。时间复杂度 O(log n),空间 O(1)。
从 Unit 01 精确查找到 Unit 02 边界查找:不再问“有没有”,而是问“切换点在哪里”
比较后立即处理“小于、等于、大于”;候选是已有元素下标,失败时区间最终为空。
把每个位置染成 False / True,始终寻找第一个 True;答案还可能是数组末尾的虚拟位置 n。
长度为n的数组存在n+1个插入位置:元素之前、元素之间以及最后一个元素之后。
第一个使 nums[i] ≥ target 成立的位置,也称第一个不小于目标的位置。
[left,right)包含left但不包含right,候选数量为 right-left。
若所有元素都小于target,答案是 len(nums);它是合法插入位置,但不是已有元素下标。
判断nums[mid]是否已经进入“≥target”的True区域。
区间演化记录
边界不变量
第一个不小于target的位置始终位于半开区间 [left,right) 中;right本身是区间外的边界标记。
mid是否保留
若nums[mid]≥target,mid仍可能是第一个True,因此执行right=mid;若nums[mid]<target,mid必然过小,执行left=mid+1。
Lower Bound不需要在循环中区分目标是否存在。它始终返回第一个不小于target的位置,最后再观察该位置的值即可判断是否命中。
在半开区间中,right不属于候选,因此循环使用left<right;当mid进入True区域时必须保留mid,执行right=mid。
若mid恰好是第一个True,会直接删除正确答案。半开区间右端只需移动到mid。
right可等于n且不属于数组下标,闭区间循环可能尝试访问nums[n]。
答案可以位于第一个元素之前、数组内部,也可以位于最后一个元素之后。
所有元素≥0
答案=0
3<4≤5
答案=2
所有元素<7
答案=n=4
len(nums)。left < right。nums[mid] < target 说明 mid 属于 False 区域,必须连同 mid 一起排除。left == right,该位置就是唯一边界,不必再次访问数组。不要直接从空白背两套二分。先把 #35 的“第一个 ≥ target”扩展为两个边界:第一个 ≥ target 与第一个 > target。
官方题意
给定一个按非递减顺序排列的整数数组 nums 和目标值 target,返回目标值在数组中的起始与结束位置;若目标不存在,返回 [-1,-1]。算法必须达到 O(log n)。
官方示例与约束
输出:[3,4]
输出:[-1,-1]
输出:[-1,-1]
0 ≤ nums.length ≤ 10⁵- 数组按非递减顺序排列,允许重复值
-10⁹ ≤ nums[i], target ≤ 10⁹
| #35 搜索插入位置 | #34 首尾位置 |
|---|---|
| 数组严格递增 | 数组非递减,目标可能重复 |
只求 lower_bound(target) | 同时求 lower_bound(target) 与 upper_bound(target) |
| 答案允许为 n | 左边界越界或不等于 target 时返回 [-1,-1] |
True 谓词:nums[i] ≥ target | 右边界外侧谓词:nums[i] > target |
lower_bound(value) 中,什么条件下向右排除?> value 时,哪些位置必须向右排除?right_exclusive = upper_bound(target),最后位置是什么?官方样例:nums=[5,7,7,8,8,10], target=8
不会自动跳转。可以继续重放 Lower/Upper Bound 轨迹,或手动进入下一单元。
第6章 Unit 02 Skill卡
搜索插入位置把二分从“是否命中”升级为“状态边界在哪里”。Lower Bound统一处理目标存在、目标缺失和插入到数组末尾的情况。