题目大意:给定一个乱序的整型数组,找出最小的缺失的正整数。 简单来说,就是找出数组中没有的最小正整数
题目分析:题目的难点在于他的要求,要求O(n)时间和常量空间。这下就直接把排序(时间复杂度不满足)和额外数组打表(空间复杂度不满足)两个方法给排除了,这是我第一反应能想到的两个方法。简单解释一下打表:常用的空间换时间方法,即用一个数组记录,数组位置上的元素放的就是 位置的值,也即 a[i] = i 或者 a[i] = i+1;总的来说,后面一般是 关于位置 i 的表达式。知道了打表,回到题目,加入不限制空间的话,那么很简单就能写出伪代码:
int a[input.size] = {0}
for i=0...input.size-1
if( input[i]>0 && input[i]<=input.size ) // 负数和超出数组大小的不要
// a[i] = i + 1, 边界a[0] = 1; a[input.size-1] = input.size
a[input[i] - 1] = input[i]
for i=0...input.size-1
if(a[i] != i+1 ) return i+1; // a[i]没有存储 i+1,则缺失
//末尾返回
return input.size+1
这个时间复杂度倒是满足了,要是不要额外的空间就好了!想到这里,思路应该清晰了。打表可不可以不开额外的数组呢?当然是可以的!就用原来的数组就好,不就是要相应位置存储相应位置数值嘛,交换就行了。直接上代码:
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
for(int i=0;i<nums.size();){
// 交换的条件:数值在数组范围内;自己位置存储不对,目标交换位置的存储也不对;
if(nums[i]>0 && nums[i]<=nums.size() && nums[i]!=i+1 &&
nums[nums[i]-1]!=nums[i]){
swap(nums[nums[i]-1], nums[i]);
} else i++; // 因为交换之后当前 i 存储的数值改变,需要进一步判断是否需要增加 i
}
// for(auto item: nums) cout <<item <<" ";
// cout <<endl;
for(int i=0;i<nums.size();i++){ // 已经交换好的数组
if(nums[i]!=i+1) return i+1; // 碰到第一个不对,就是你了!
}
return nums.size()+1;
}
};
结果有点喜人