- 方法1:
直接使用哈希表存储,再逐个寻找没有出现的最小正整数,时间复杂度为 O(n), 空间复杂度为 O(n);
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
unordered_set<int> count_set;
for (auto& num : nums) {
count_set.insert(num);
}
for (int i = 1; i < INT_MAX; ++i) {
if (!count_set.count(i)) {
return i;
}
}
return -1;
}
};
- 方法2:原地哈希
利用数组的索引作为哈希表的位置,将每个元素放置到其对应的索引位置。这样,我们可以在原地进行操作,不需要额外的空间。
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n = nums.size();
// 将负数和大于n的数置为n+1(这些数不影响结果)
for (int& num : nums) {
if (num <= 0 || num > n) {
num = n + 1;
}
}
// 标记出现过的数字为负数
for (int i = 0; i < n; ++i) {
int num = abs(nums[i]);
if (num <= n) {
nums[num - 1] = -abs(nums[num - 1]);
}
}
// 查找第一个未标记的索引
for (int i = 0; i < n; ++i) {
if (nums[i] > 0) {
return i + 1;
}
}
// 如果所有的 1 到 n 都出现了,则返回 n+1
return n + 1;
}
};
解释:
- 预处理:将数组中所有负数和大于
n
的数标记为n + 1
,因为这些数不会影响到最小缺失正整数的结果。 - 标记:遍历数组,将每个出现的数字的对应位置标记为负数(使用绝对值),以表示该数字出现过。
- 查找:再次遍历数组,查找第一个未被标记的位置,返回
i + 1
作为结果。如果所有位置都被标记过,返回n + 1
。
复杂度:
- 时间复杂度:O(n) —— 由于只进行了一次遍历来标记,和一次遍历来查找结果。
- 空间复杂度:O(1) —— 除了输入数组外没有使用额外空间。