思路一:哈希表法
对于一个长度为n的数组,其中没有出现的最小正整数必然在[1,n+1]内,其中 n 是数组的长度。因此,为了找到这个最小缺失的正整数,我们可以按以下步骤操作:
- 将数组中的所有正整数(大于 0 的数字)放入一个哈希表中,确保只存储有效的正整数。
- 然后从
1开始,逐一检查哈希表中是否存在这些数字(即检查[1, n]范围内的数字)。 - 如果在这个范围内找到了某个缺失的数字,那么这个数字就是我们要找的最小缺失正整数。
- 如果
1到n的所有数字都存在,那么最小缺失的正整数就是n + 1。
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n = nums.size();
unordered_set<int> arr(n);
//将正整数复制到哈希表中
for(int &i: nums){
if(i > 0){
arr.emplace(i);
}
}
//查找[1,n]中的所有数字是否全部存在
for (int min_num = 1; min_num <= n; min_num++) {
if (arr.find(min_num) == arr.end()) {
return min_num;
}
}
return n + 1;
}
};
- 时间复杂度O(n)
- 空间复杂度O(n)
思路二:原地哈希法
从哈希表获得启示,对于遍历到的在 [1, n] 范围内的数字进行标记,标记的方法是将该数字对应的所以位置打上 负号,如对于数组【1,2,0】,当遍历到1时会将索引0的数字,也就是1打上符号,这时数组就变成了【-1,2,0】,再次从头遍历数组,第一个遍历到的非负数就是缺失的第一个正整数,如果都是负数,那么缺失的第一个正整数就是n+1
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n = nums.size();
//将不在【1,n】范围内的数字置为n+1
for (int& num: nums) {
if (num <= 0) {
num = n + 1;
}
}
//将在【1,n】范围内的数字对应的索引位置的数字置为负数
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;
}
};
-
时间复杂度:O(N)。
-
空间复杂度:O(1)。
思路三:置换
- 将数组中的每个数组都放回它本来应该在的位置,比如数字3应该放在索引位置为2的地方
- 在【1,n】 内寻找缺失的数字,找到第一个不满足
nums[i] == i + 1的位置,返回i + 1作为缺失的最小正整数 - 如果均不缺失,就返回n+1
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n = nums.size();
for (int i = 0; i < n; ++i) {
while (nums[i] > 0 && nums[i] <= n && nums[nums[i] - 1] != nums[i]) {
swap(nums[nums[i] - 1], nums[i]);
}
}
for (int i = 0; i < n; ++i) {
if (nums[i] != i + 1) {
return i + 1;
}
}
return n + 1;
}
};
-
时间复杂度:O(N)。
-
空间复杂度:O(1)。
1851

被折叠的 条评论
为什么被折叠?



