35. 搜索插入位置

简单 含交互动画

学完这道你应该能: 说清它为什么用「二分查找」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

AI 私教 · 就着本题动画讲
卡住了不用硬扛,按 8 步把这题真正走通。
从读题、试解、找法到手写代码,边问边打勾,适合第一次系统学算法的同学。

题目描述

升序数组中找 target,存在返回下标;不存在返回它按序应插入的位置

nums = [1, 3, 5, 6]
target = 2
输出 = 1

思路解析

挨个比当然能找到第一个 ≥ target 的位置,可那是 O(n)。数组明明是升序的,把这个条件用起来,就能砍到 O(log n)。

转折:升序数组里「nums[i] ≥ target」一旦成立,后面就全成立——这是一条单调的真/假分界。二分要找的就是这条分界的左端。不变量:始终保证答案落在 [l, r] 里——nums[mid] ≥ target 时答案可能就是 mid,所以收 r=mid(不减 1);nums[mid] < target 时 mid 太小,l=mid+1。最后 l 就是答案。

准备 · 半开区间 [0,4):这里 r 取 len=4(注意能等于长度,因为答案可能是「插在最末尾」)。l=0。要找第一个 ≥ 2 的位置。

第 1 轮 · 取 mid:中点 mid=2,nums[2] = 5。拿它和 target=2 比,决定收哪边。

第 1 轮 · 判断:5 ≥ 2,说明 mid=2 这个位置「满足条件」,它有可能就是答案,但右边更不可能是答案。所以收右边,但 r 收到 mid 而不是 mid−1(别把 mid 自己丢了)。

第 1 轮 · 收缩:r 收到 2,范围变成 [0, 2)。下标 2、3(灰)整段丢掉。注意 mid=2 虽是候选,但它右边的更大值不可能更优,所以一起丢。

第 2 轮 · 取 mid:范围 [0, 2),新中点 mid=1,nums[1] = 3

第 2 轮 · 判断:3 也 ≥ 2,下标 1 仍是候选。继续往左缩,r 收到 mid=1。

第 2 轮 · 收缩:r 收到 1,范围 [0, 1),只剩下标 0 没判。

第 3 轮 · 取 mid(负例分支):这轮是另一种分支:mid=0,nums[0]=1 比 target 小。1 排不到 2 前面,下标 0 不可能是插入位置

第 3 轮 · 收缩 → l 越过:nums[mid] 太小,mid 及左边全丢,l 跳到 mid+1=1。现在 l == r == 1,区间空了,循环结束。

返回 l:收尾时 l = 1 就是答案:2 插在下标 1,数组变 [1,2,3,5,6] 仍升序。无论 target 在不在数组里,返回的都是 l。

只要能把问题变成「第一个满足某条件的位置」,就是 lower_bound:r=mid 留候选、l=mid+1 弃旧,最后返回 l。x 的平方根、第一个错误版本都是这个模板。

参考代码(Python)

Python
1def searchInsert(self, nums, target):
2    l, r = 0, len(nums)              # 半开区间 [l, r),r 可等于 len
3    while l < r:                     # 注意是 < 不是 <=
4        mid = l + (r - l) // 2       # 取中点,防溢出
5        if nums[mid] >= target:
6            r = mid                  # mid 是候选,收 r=mid 不减 1
7        else:
8            l = mid + 1              # mid 太小,丢掉它
9    return l                         # 找不到也返回 l,就是插入位置

复杂度分析

  • 时间复杂度:O(log n) —— 每轮把搜索区间砍掉一半
  • 空间复杂度:O(1) —— 只用 l、r、mid 三个变量

套路模板

三处要点:while l < r、r=mid 不减 1、返回 l。这套「找下界」模板比 ≤ 版更适合「找第一个满足条件的位置」。

Python
1l, r = 0, len(nums)        # 半开 [l, r)
2while l < r:
3    mid = l + (r - l) // 2
4    if check(mid):         # nums[mid] >= target
5        r = mid           # 留候选
6    else:
7        l = mid + 1       # 弃旧
8return l                   # 第一个满足的位置

易错点

  • 错误写法:找不到时返回 -1正确写法:返回 l(就是插入位置)(本题求的是插入位置,不存在时 l 正好停在该插入的下标,返回 -1 是把它当普通查找做错了)
  • 错误写法:nums[mid] >= target 时写 r = mid - 1正确写法:r = mid(不减 1)(mid 自己可能就是第一个满足的位置,减 1 会把答案丢掉,导致结果偏小)
  • 错误写法:r 初始化成 len(nums) - 1正确写法:r = len(nums)(target 比所有数都大时插入位置是末尾 len,r 少 1 就够不到)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →33. 搜索旋转排序数组 ← 返回题库