41. 缺失的第一个正数
给你一个未排序的整数数组 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
代码一
这种方法有点暴力,得多注意边界的判断等,有点麻烦,得多考虑 [-1,0,3,1] 这个样例。这种写法的空间和时间都不符合题意
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
sort(nums.begin(),nums.end());
auto num=unique(nums.begin(),nums.end());
nums.erase(num,nums.end());
//cout<<nums.size()<<endl;
int ls=nums.size();
int minnum=1;
bool flag=false;
int t=0;
vector<int> w;
for(int i=0;i<ls;i++){//保证非负
if(nums[i]>0){
t=i;
flag=true;
w.push_back(nums[i]);
}
}
sort(w.begin(),w.end());
int len=w.size();
if(!flag||(len==1&&w[0]!=1)) return 1;//不存在非负,或者整个数组的长度只有1时
for(int i=0;i<len;i++){
if(w[i]==minnum){
minnum++;
}
else if(w[i]!=minnum&&i+1==len)//处理数组的右边界
{
if(minnum+1<=nums[i]){
return minnum;
}
else{
return minnum++;
}
}
else if(w[i]!=minnum&&i+1!=len){//处理中间部分缺失的情况
break;
}
}
return minnum;
}
};
代码二
存在映射关系,设计哈希表,空间复杂度为O(1),将原数组设计成哈希表,负数换成n+1,这样的数不在考虑范围内,合理的处理了负数对于整个数组的影响,给正数打负号标记,来判断缺失哪个数
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int len=nums.size();
for(int& num:nums){//处理负数的不合法
if(num<=0){
num=len+1;
}
}
for(int i=0;i<len;i++){
int num = abs(nums[i]);
if(num<=len){
nums[num-1] = -abs(nums[num-1]);
}
}
for(int i=0;i<len;i++){
if(nums[i]>0){
return i+1;
}
}
return len+1;
}
};
代码三
找到最小的整数,可以不开新的空间的条件下,把数组中的正数放在合法位置,在进行遍历即可,需要注意的是有 nums[i]=x=nums[x−1]这个会陷入死循环,排除这个情况即可。
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int len = nums.size();
for (int i = 0; i < len; i++) {
while (nums[i] > 0 && nums[i] <= len && nums[nums[i] - 1] != nums[i]) {
swap(nums[nums[i] - 1], nums[i]);
}
}
for (int i = 0; i < len; i++) {
if (nums[i] != i + 1) {
return i + 1;
}
}
return len + 1;
}
};