给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。
本题的思路是,一个长度为 N 的数组,其中没有出现的最小正整数只能在 [1,N+1] 中。这是因为如果 [1,N] 都出现了,那么答案是 N+1,否则答案是 [1,N] 中没有出现的最小正整数。
因此,对数组进行遍历,对于遍历到的数 x,如果它在 [1,N] 的范围内,那么就将数组中的第 x−1 个位置(注意:数组下标从 0 开始)打上「标记」。在遍历结束之后,如果所有的位置都被打上了标记,那么答案是 N+1,否则答案是最小的没有打上标记的位置加 1。
1.将数组中所有小于等于 0 的数修改为 N+1;
2.遍历数组中的每一个数 x,它可能已经被打了标记,因此原本对应的数为 ∣x∣,其中 ∣∣ 为绝对值符号。如果 ∣x∣∈[1,N],那么我们给数组中的第 ∣x∣−1 个位置的数添加一个负号。注意如果它已经有负号,不需要重复添加;
3.在遍历完成之后,如果数组中的每一个数都是负数,那么答案是 N+1,否则答案是第一个正数的位置加 1。
代码如下:
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int len = nums.size(); // 获取数组的长度
// 将所有小于等于 0 的数替换为 len + 1
for(int& num : nums) {
if(num <= 0) {
num = len + 1;
}
}
// 对于绝对值小于等于 len 的数,将其对应位置的数变为负数
for(int i = 0; i < len; i++) {
int cur = abs(nums[i]);
if(cur <= len) {
nums[cur - 1] = -abs(nums[cur - 1]);
}
}
// 查找第一个正数所在的位置,返回其索引 + 1 ,即为第一个缺失的正数
for(int i = 0; i < len; i++) {
if(nums[i] > 0) {
return i + 1;
}
}
// 如果遍历完都没找到正数,说明缺失的正数是 len + 1
return len + 1;
}
};