跳到正文
第 41 题困难

缺失的第一个正数

First Missing Positive

找出数组中没有出现的最小正整数,要求时间 O(n)、空间 O(1)。

在力扣中练习

题目描述

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

 

示例 1:

输入:nums = [1,2,0]
输出:3
解释:范围 [1,2] 中的数字都在数组中。

示例 2:

输入:nums = [3,4,-1,1]
输出:2
解释:1 在数组中,但 2 没有。

示例 3:

输入:nums = [7,8,9,11,12]
输出:1
解释:最小的正数 1 没有出现。

 

提示:

  • 1 <= nums.length <= 105
  • -231 <= nums[i] <= 231 - 1

解题思路

主解法

原地哈希 · 值放回下标

值 v 应该待在下标 v-1

如果可以用哈希集合,先把所有正数装进去,再从 1 开始逐个查,答案立刻出来;但空间是 O(n)。

利用数组本身当下标表:值 v(1 ≤ v ≤ n)应该放在下标 v-1。遍历每个位置,如果当前值在范围内且目标位置不是同一个值,就交换过去,直到当前值无法归位。

自拟主例 [2,5,1,4,6]:2 换到下标 1,换来的 5 继续换到下标 4,最后 1 归位,数组变成 [1,2,6,4,5]。

分步图解

nums[0] = 2 属于下标 1,交换过去;第 1 次交换。

i
0
target
1
nums
0
1
2
3
4
5→ 4
2
1
4
6
i
值 v 应该放在下标 v-1;绿色表示已经就位
1 / 3
2 换到下标 1,换来的 5 继续追上标 4;6 超出范围,留在原地。

最后从下标 0 扫描,第一个 nums[i] != i+1 的位置,答案就是 i+1;都正确则返回 n+1。

图解
nums
0
1
2
3
4
1
2
6
4
5
扫描
值 v 应该放在下标 v-1;绿色表示已经就位
普通节点当前操作已确认 / 结果排除 / 冲突
1 就位后,下标 3、4 也对了;扫描到下标 2 发现 6 而不是 3,返回 3。

每个数最多被交换到正确位置一次,时间 O(n),空间 O(1)。

时间 O(n)空间 O(1)

易错点

  • while 条件少了“目标位置值不同”:重复值会在两个位置之间无限交换。
  • 只处理正数却忘了 <= n 的上界:nums[i] 可能远大于 n,会越界。
  • 扫描时从 1 开始找值:应该检查 nums[i] 是否等于 i+1。
  • 所有 1..n 都出现时忘记返回 n+1。
对照解法

哈希集合 · O(n) 空间

把所有数装进集合,从 1 开始逐个查

时间 O(n),但需要 O(n) 额外空间;主解法利用数组本身当下标表,满足空间 O(1)。

最直观的做法:把数组元素放进哈希集合,然后从 1 开始依次问“在不在集合里”,第一个不在的就是答案。

时间 O(n),空间 O(n)。它不受“值必须落在 1..n”的限制,思路简单,适合先写出正确版本。

  1. 1所有元素放入集合。
  2. 2candidate 从 1 开始。
  3. 3集合包含 candidate 就 ++candidate。
  4. 4返回 candidate。
时间 O(n)空间 O(n)

易错点

  • 从 0 开始找:0 不是正整数,答案最小是 1。
  • 只遍历原数组的最大值:如果 1..max 都出现,答案可能是 max+1。

代码与演示

主解法配有图解;对照解法用于比较思路、复杂度或实现方式。

演示输入nums = [2,5,1,4,6]

把 1..n 范围内的数尽量放回自己的位置:值 v 放到下标 v-1。

n
5
nums
0
1
2
3
4
2
5
1
4
6
值 v 应该放在下标 v-1;绿色表示已经就位
1 / 9
查看 C++ 代码

延伸阅读

  • “值 v 放到下标 v-1”是原地哈希的典型手法,也用于找到重复数、缺失数等问题。
  • 如果题目不要求 O(1) 空间,哈希集合最稳;先写对再考虑压缩空间。