448 找到所有数组中消失的数字
题目理解
数组元素在1~n范围内,找到所有缺少的数字。要求不使用
额外空间且时间复杂度为O(n)。
思路
最简单的方法是建立map,将1~n每个数字出现的次数存在map中。考虑不使用额外空间,则需要给已经出现的数字一个标记。类似上文,遍历数组,令a[i]位置的元素取负,当遇到重复元素时,a[i]位置的元素仍为负数,不执行操作,因此最终缺少的元素,以此为下标的数组元素必为正数。
代码
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
vector<int> res;
int n=nums.size();
for(auto i:nums){
if(nums[abs(i)-1]>0)
nums[abs(i)-1]*=-1; //一定是i的绝对值,因为原数组中的元素可能已经取反。
}
for(int j=0;j<n;j++)
if(nums[j]>0)
res.push_back(j+1);
return res;
}
};
442 数组中重复的元素
题目理解
数组元素范围1~n,数组中有两种数,一种是只出现一次的数,一种是出现两次的数。找出所有出现两次的元素。
思路
与上题类似,只要在遍历数组时,遇到数组元素已经为负,说明此下标+1代表的数字已经出现过,即为所求。
代码
class Solution {
public:
vector<int> findDuplicates(vector<int>& nums) {
vector<int> res;
int n=nums.size();
for(auto i:nums){
if(nums[abs(i)-1]<0)
res.push_back(abs(i));
else nums[abs(i)-1]*=-1;
}
return res;
}
};
41 缺失的第一个正数
题目理解
整数数组未排序,其中可能有正数、负数、0,因此上面取负的方法失去作用。进阶是实现时间复杂度为O(n),空间复杂度为常数级别。寻找缺失的第一个正数。
思路
寻找的是缺失的第一个正数,因此负数和0不需要考虑。怎样消除负数和0的影响是需要解决的一个问题。起初我的想法是将所有的负数和0转化为1,前提是要判断1是否缺失。这样再采用取负的方法,遇到的第一个大于0的数的下标+1即为所求。题解中给的思路是将所有小于等于0的元素变为n+1,即可使用取负,思路类似。
第二种思路是将所有的正数与数组下标对应起来,因此需要循环交换数组元素。第一个与元素下标+1不同的元素即为所求。
代码
①
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n=nums.size();
int flag=0;
for(auto& i:nums)
if(i==1)
flag=1;
if(!flag) return 1;
for(auto& i:nums)
if(i<=0)
i=1;
for(auto& i:nums)
{
if(i<=n&&nums[abs(i)-1]>0) //切记要加i<=n的判断,否则数组会越界
nums[abs(i)-1]*=-1;
}
for(int i=0;i<n;i++)
if(nums[i]>0)
return i+1;
return n+1;
}
};
②
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n=nums.size();
for(int i=0;i<n;i++)
{
while(nums[i]>=1&&nums[i]<=n&&nums[nums[i]-1]!=nums[i])//条件避免死循环
swap(nums[i],nums[nums[i]-1]);
}
for(int i=0;i<n;i++)
if(nums[i]!=i+1)
return i+1;
return n+1;
}
};