LeetCode41-缺失的第一个正数
41. 缺失的第一个正数:
给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。
示例 1:
输入:nums = [1,2,0]
输出:3
示例 2:
输入:nums = [3,4,-1,1]
输出:2
示例 3:
输入:nums = [7,8,9,11,12]
输出:1
提示:
- 1 <= nums.length <= 5 * 10^5
- -2^31 <= nums[i] <= 2^31 - 1
思路:
容易想到O(n^2)算法,直接两个循环暴力寻找某个数是否出现。
或者用一个vis数组来判断某个数是否出现过。
都不满题目的要求。
如何进行优化是我们需要思考的问题,官方题解写得非常的详细。
官方题解
解题思路1:
用于不能多开数组,但是原数组确实可以改变的,我们用正负数来判断i这个位置是否出现过,正数表示未出现过,负数表示i这个数出现过。
注意:最小正整数不会超过len+1(len为nums长度)
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int len=nums.size();
for(int i=0;i<len;++i) {
if(nums[i]<=0)
nums[i]=len+1;
}
for(int i=0;i<len;++i) {
int x=abs(nums[i]);
if(x<=len)
nums[x-1]=-abs(nums[x-1]); //有可能有相同的数,变两次可能又变回了正数,所以加一个abs
}
for(int i=0;i<len;++i) {
if(nums[i]>0)
return i+1;
}
return len+1;
}
};
解题思路2:
置换,在对应区间[1,len]的数置换到对应位置i,注意两个数有可能相同,不能一直置换
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[i]!=i+1 && nums[i]!=nums[nums[i]-1])
swap(nums[i],nums[nums[i]-1]);
}
for(int i=0;i<len;++i) {
if(nums[i]!=i+1)
return i+1;
}
return len+1;
}
};