二分查找不只是找数:Search Insert Position 的本质理解

21 阅读3分钟

LeetCode 35|Search Insert Position
关键词:二分查找、边界处理、返回 left 的真正含义


一、题目到底在考什么?

题目描述很简单:

  • 给你一个 升序数组 nums
  • 给你一个目标值 target
  • 如果数组中存在 target,返回它的下标
  • 如果不存在,返回 按顺序插入后的位置下标

示例:

nums = [1,3,5,6], target = 52
nums = [1,3,5,6], target = 21
nums = [1,3,5,6], target = 74
nums = [1,3,5,6], target = 00

乍一看像“找位置”,但本质是:

在有序数组中,找到第一个「大于等于 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 > 2right=0

left=0, right=0
mid=0 → nums[0]=1 < 2left=1

循环结束:left=1, right=0

此时:

[1] < 2
[3,5,6] > 2

插在 13 中间的位置,正好是下标 1


五、为什么不能返回 right?

这是很多人容易犯的错误。

  • right 指向的是 最后一个小于 target 的元素
  • 插入位置应该在它的 后面
  • right + 1,恰好等于 left

所以:

插入位置 = left,而不是 right


六、这道题的“隐藏能力”:通用性极强

这道题的写法,其实是一个非常重要的模板:

查找“第一个 >= x 的位置”

它可以直接迁移到很多场景:

  • 查找第一个大于等于目标值的元素
  • lower_bound(C++)
  • 插入排序中的定位
  • 去重、区间统计问题

你现在掌握的不是一道题,而是一类问题。


七、时间与空间复杂度分析

时间复杂度

O(log n)

每次循环缩小一半区间。

空间复杂度

O(1)

只使用了常数级变量。


八、常见易错点总结

  1. while (left <= right) 不要写成 <
  2. mid 推荐写成:
left + (right - left) / 2

防止溢出(好习惯)
3. 找不到时,一定返回 left
4. 不要在循环外额外判断插入位置


九、总结一句话版

Search Insert Position 本质不是“找没找到”,而是“该放哪”。
而二分查找中的 left,正好就是答案。