LeetCode算法网站算法题
https://leetcode-cn.com/problems/first-missing-positive/
一.原地哈希
思路:
1.先把数组中负数全部赋值n+1;
2.给予正确出现的数字为下标的元素标记;
3.再次遍历数组,返回第一个正数的下标+1。
注意:
在第二步处理中,对每一个遍历元素进行只读的abs处理很重要,否则很可能在之前的遍历中,当前位置的元素已经被标记了从而被修改为负数,
那么本来正确出现的数字就不会被统计上,从而出错。
其次,对标记时的abs处理也很重要,因为如果某个范围内的值出现了两次,那么当前位置会被标记两次,导致负负得正,标记丧失。
class Solution
{
public:
int firstMissingPositive(vector<int>& nums)
{
int n=nums.size();
for(int i=0;i<n;i++)//把负数标记为n+1,因为n+1是判断范围之外的一个值
{
if(nums[i]<=0)
nums[i]=n+1;
}
for(int i=0;i<n;i++)
{
int num=abs(nums[i]);//这里的处理很关键,因为很可能在之前的遍历中,当前位置的元素已经被标记了从而被修改为负数,那么本来正确出现的数字就不会被统计上,从而出错
if(1<=num&&num<=n)
{
//这里的abs处理也很重要,应为可能重复出现的两个元素会反复修改当前值,导致标记消失
nums[num-1]=-abs(nums[num-1]);//num-1是为了控制下标问题,对正确出现的正整数进行标记,使得正确出现的正整数下标的数据标记为负数
}
}
int i;
//不用担心重复出现的情况,因为如果重复出现的话,以正确的返回值-1为下标的元素任然不会被标记
for(i=0;i<n;i++)
{
if(nums[i]>0)
break;
}
return i+1;
}
};
二.置换:让正确的值去对应的位置上
第一次遍历交换使用循环的必要性:
如果使用if语句的话就只会判断一次,那么有可能这一次交换之后当前位置出现的是范围内的值,但是不会被再次交换到正确的位置上,导致出错。如:3,4,-1,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])//使用循环的必要性:
// 如果使用if语句的话就只会判断一次,那么有可能这一次交换之后当前位置出现的是范围内的值,但是不会被再次交换到正确的位置上,导致出错。如:3,4,-1,1
{
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;
}
};
简单暴力:
class Solution
{
public:
int firstMissingPositive(vector<int>& nums)
{
sort(nums.begin(), nums.end());
int ans = 1;
for (const int n : nums)
{
if (n == ans)
{
++ans;
}
}
return ans;
}
};