LeetCode 35|Search Insert Position
关键词:二分查找、边界处理、返回 left 的真正含义
一、题目到底在考什么?
题目描述很简单:
- 给你一个 升序数组 nums
- 给你一个目标值
target - 如果数组中存在
target,返回它的下标 - 如果不存在,返回 按顺序插入后的位置下标
示例:
nums = [1,3,5,6], target = 5 → 2
nums = [1,3,5,6], target = 2 → 1
nums = [1,3,5,6], target = 7 → 4
nums = [1,3,5,6], target = 0 → 0
乍一看像“找位置”,但本质是:
在有序数组中,找到第一个「大于等于 target」的位置
二、为什么第一反应一定是二分查找?
因为题目已经给了一个非常强的暗示:
- 数组是 升序
- 要找的是 位置
这正是二分查找最擅长的场景:
- 时间复杂度从
O(n)降到O(log n) - 同时还能优雅地处理“找不到”的情况
三、代码实现(标准模板)
你现在用的实现,其实就是二分查找的黄金模板之一:
class Solution {
public int searchInsert(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) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return left;
}
}
重点不在 while 里,而在 最后一行 return left。
四、为什么找不到时,返回的一定是 left?
这是整道题最核心、最容易模糊的地方。
我们拆开来看。
1️⃣ 循环结束的条件是什么?
while (left <= right)
循环结束时,一定是:
left > right
此时数组被划分成了三个区间(逻辑上):
[0 ... right] < target
[left ... end] > target
而且注意:
right + 1 == left
2️⃣ left 指向的是什么位置?
在整个二分过程中:
left只会在nums[mid] < target时右移- 所以它永远指向第一个「可能放 target 的位置」
也就是说:
left 指向的是第一个 >= target 的下标
这正是“插入位置”的定义。
3️⃣ 用一个具体例子走一遍
nums = [1,3,5,6]
target = 2
过程:
初始:left=0, right=3
mid=1 → nums[1]=3 > 2 → right=0
left=0, right=0
mid=0 → nums[0]=1 < 2 → left=1
循环结束:left=1, right=0
此时:
[1] < 2
[3,5,6] > 2
插在 1 和 3 中间的位置,正好是下标 1。
五、为什么不能返回 right?
这是很多人容易犯的错误。
right指向的是 最后一个小于 target 的元素- 插入位置应该在它的 后面
- 而
right + 1,恰好等于left
所以:
插入位置 = left,而不是 right
六、这道题的“隐藏能力”:通用性极强
这道题的写法,其实是一个非常重要的模板:
查找“第一个 >= x 的位置”
它可以直接迁移到很多场景:
- 查找第一个大于等于目标值的元素
- lower_bound(C++)
- 插入排序中的定位
- 去重、区间统计问题
你现在掌握的不是一道题,而是一类问题。
七、时间与空间复杂度分析
时间复杂度
O(log n)
每次循环缩小一半区间。
空间复杂度
O(1)
只使用了常数级变量。
八、常见易错点总结
while (left <= right)不要写成<mid推荐写成:
left + (right - left) / 2
防止溢出(好习惯)
3. 找不到时,一定返回 left
4. 不要在循环外额外判断插入位置
九、总结一句话版
Search Insert Position 本质不是“找没找到”,而是“该放哪”。
而二分查找中的 left,正好就是答案。