题目如下
数据范围
观察数据范围n方复杂度的算法铁定不行了。但是我们可以另辟蹊径:
若一个数组长度为n且这个数组的数都是正常的(例如 n = 3 [1,2,3])
这样即返回答案最大为n + 1
若出现不正常数(例如 n = 3 [1,2,5] [1,1,2])那么显然答案应该是3 是小于n + 1的
所以我们不妨这样推断如果这个数组正常那么每个数必然能刚好对应一个位置就像上面的正常数组
1在0 2在1 3在2 即出现nums[i] == i + 1。
即使数组不正常那么至少存在一段正常的子数组(除了没有1的数组外)即例如
[-1,1,2,3,-9]其中我们能看见1 2 3是正常的子数组,当然我们不要求这个子数组连续但是要从1开始且每次加一。[-1,1,4,2,-10101]那么1 2 是正常子数组。所以这里有一个结论所有大数组的正常子数组的长度是小于等于大数组的长度的。
那么我们就可以原地利用这个nums当我们遇到1个正常数(大于0且大小要小于nums中正数的个数count,
因为从1开始最极端的情况就每个正数都出现即从1到count如果大于count那么未出现的正数必然在这个数之前,故这个正数不用在意)
注意:在交换位置的时候要检查是不是把正常数交换到前面已经遍历的位置且交换来的数不应该在这个位置,
通过一个循环不断使得每个正常数到自己的位置。
通过代码
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n = nums.size();
int count = 0;
int pre = -1;
for(int i = 0;i < n;i++){
if(nums[i] > 0)count++;
if(nums[i] == 1)pre = 0;
}
// if(count == n)return n + 1;
if(pre == -1)return 1;
for(int i = 0;i < n;i++){
if(nums[i] > 0){
if(nums[i] > count){
continue;
}
pre = i;
swap(nums[nums[i] - 1],nums[i]);
}
while(nums[i] > 0 && i + 1 != nums[i]){//检查
if(nums[i] > count || nums[i] == nums[nums[i] - 1]){//最后一个检查是防止有重复正常数而陷入死循环
break;
}
swap(nums[nums[i] - 1],nums[i]);
}
}
for(int i = 0;i < n;i++){
//cout << nums[i] << " ";
if(i + 1 != nums[i])return i + 1;
}
return n + 1;
}
};