41. 缺失的第一个正数
1. 题目
41. 缺失的第一个正数 - 力扣(LeetCode)
2. 解题思路
2.1. 理想状态
数组长度是 n
,那么我们只关心 1 到 n 这些数字。
如果一切完美,数组应该长这样:
下标: 0 1 2 3 ... n-1
数值: 1 2 3 4 ... n
也就是 数值 = 下标+1。
[!question] 为什么只关心1到n
因为求的是缺失的最小的正整数,所以我们只要关心到n
。
- 如果数组里 1…n 这些数都出现了,那么前 n 个正整数就全齐了,缺失的第一个正数只能是 n+1。
- 如果数组里 1…n 里有某个没出现,那缺失的第一个正数一定落在这段范围里。
换句话说:答案一定在 1…n+1 之间,不会比 n+1 更大。
2.2. 把数放回该在的位置
如果某个数 x
在 1…n 之间,那它应该待在位置 x-1
上。
所以我们扫描数组,发现不对劲就交换:
- 举个例子:数值
3
出现在下标0
上,它应该去下标2
。 - 于是我们把它和下标
2
的数交换。
这样反复交换,最后所有合法的数都会“归位”。
2.3. 答案匹配
- 如果某个数缺失了,那它对应的位置一定不会对上。
比如2
不存在,那么在下标1
上就不可能出现2
,最后一定能发现。 - 扫描一遍数组:
- 如果第一个不匹配的是
i
位置,那缺的就是i+1
。 - 如果全部都对上了,说明
1..n
全都存在,缺的就是n+1
。
- 如果第一个不匹配的是
2.4. 举例[3, 4, -1, 1]
- 长度是 4,我们只关心数字
1..4
。 - 开始放数归位:
- 下标 0 是 3,不对 → 和下标 2 交换 →
[ -1, 4, 3, 1 ]
- 下标 0 是 -1(无效数),跳过
- 下标 1 是 4,不对 → 和下标 3 交换 →
[ -1, 1, 3, 4 ]
- 下标 1 是 1,不对 → 和下标 0 交换 →
[ 1, -1, 3, 4 ]
- 下标 0 是 3,不对 → 和下标 2 交换 →
- 此时数组变成
[1, -1, 3, 4]
。 - 扫描:
- 位置 0 对上(1)。
- 位置 1 错(应该是 2,实际是 -1)。
- 所以缺的就是 2。
3. 代码
3.1. 完整代码
class Solution {public int firstMissingPositive(int[] nums) {int n = nums.length;for (int i = 0; i < n; i++) {while (nums[i] > 0 && nums[i] <= n && nums[i] != i + 1) {int correctIndex = nums[i] - 1;// 如果目标位置已经是同样的数,就不要交换,避免死循环,比如case:[1,1]if (nums[correctIndex] == nums[i]) {break;}int temp = nums[correctIndex];nums[correctIndex] = nums[i];nums[i] = temp;}}for (int i = 0; i < n; i++) {if (i + 1 != nums[i]) {return i + 1;}}return n + 1;}
}
3.2. 注意点
while
循环中:nums[i] != i + 1
,如果一直交换不到正确数字会死循环吗?
不会的。只有在「当前数值在有效范围 1…n 且不在自己该在的位置」时才交换。