集合 s
包含从 1
到 n
的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 。
给定一个数组 nums
代表了集合 S
发生错误后的结果。
请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。
示例 1:
输入:nums = [1,2,2,4] 输出:[2,3]
示例 2:
输入:nums = [1,1] 输出:[1,2]
思路一:映射关系
//映射的思路,将nums中的数字同下标建立映射关系
class Solution {
public:
vector<int> findErrorNums(vector<int>& nums) {
int n=nums.size();
int dup=-1;
for(int i=0;i<n;i++)
{
int index=abs(nums[i])-1;
if(nums[index]<0)
{
dup=abs(nums[i]);
}
else
{
nums[index]*=-1;
}
}
int missing=-1;
for(int i=0;i<n;i++)
{
if(nums[i]>0)
{
missing=i+1;
}
}
return vector<int>({dup,missing});
}
};
思路二:数学法
//数学法
//先排序,排序后的数组中,相邻两个数字相等的就是重复的那个数字
//丢失的那个数字=重复的那个数字-(nums数组中所有数字之和-从1~n的整数之和)
//例如:nums = [1,2,2,4],lose=2-(9-10)=3
class Solution {
public:
vector<int> findErrorNums(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<int> res;
for(int i=1;i<nums.size();i++)
{
if(nums[i]==nums[i-1])
{
res.push_back(nums[i]);
}
}
int sum=(1+nums.size())*nums.size()/2;
int lose=res[0]-(accumulate(nums.begin(),nums.end(),0)-sum);
res.push_back(lose);
return res;
}
};
给你一个含 n
个整数的数组 nums
,其中 nums[i]
在区间 [1, n]
内。请你找出所有在 [1, n]
范围内但没有出现在 nums
中的数字,并以数组的形式返回结果。
示例 1:
输入:nums = [4,3,2,7,8,2,3,1] 输出:[5,6]
示例 2:
输入:nums = [1,1] 输出:[2]
思路:
可以用哈希表存每一个元素,最后遍历哈希表,看缺少1~n之间的哪个数。
上述做法空间复杂度为O(N),我们可以直接让nums充当哈希表,原地修改。
由于nums的数字范围均在[1,n]中,我们可以利用这一范围之外的数字,来表达“是否存在”的含义。
具体来说,遍历nums,每遇到一个数x,就让 nums[x-1]增加 n。由于nums中所有数均在 [1,n]中,增加以后,这些数必然大于n。最后我们遍历nums,若nums[i]未大于n,就说明没有遇到过数 i+1,这样我们就找到了缺失的数字。
注意,当我们遍历到某个位置时,其中的数可能已经被增加过,因此需要对n取模来还原出它本来的值。
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
int n=nums.size();
vector<int> ans;
for(int i=0;i<n;i++)
{
int index=(nums[i]-1)%n;
nums[index]+=n;
}
for(int i=0;i<n;i++)
{
if(nums[i]<=n)
{
ans.push_back(i+1);
}
}
return ans;
}
};
给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗?
以任意顺序返回这两个数字均可。
示例 1:
输入: [1]
输出: [2,3]
示例 2:
输入: [2,3]
输出: [1,4]
思路:数学法
因为数组nums中的数字不重复,所以缺失的两数之和除以二的值" mid "一定在缺失的两数之间(比小的大,比大的小),再计算1~mid的总和,减去nums中在1~mid之间已经存在的整数,那么剩下的肯定就是缺失的两数中左边的那个。
例如:nums=[1,2,3,5,6,7,9]
缺失两数之和为12 (4+8),除以2是6 (4和8在6的一左一右),1 + 2 + ... + 6 = 21,减去nums中已经存在的6左边的数,即1+2+3+5+6=17,得4(因为这里面少加了4嘛),12-4=8得到另一个数。
class Solution {
public:
vector<int> missingTwo(vector<int>& nums) {
int n=nums.size()+2;//数组原本的长度
int sum=(1+n)*n/2;//数组原本的元素和(1~n的整数和)
int missTwoSum=sum-accumulate(nums.begin(),nums.end(),0);//缺失的两数之和
int mid=missTwoSum/2;//缺失的两数之和/2
int midSum=(1+mid)*mid/2;//1~mid的整数和
for(int v:nums)
{
if(v<=mid)
{
midSum-=v;//减去位于mid左边的nums中的数,得到缺失的两数中左边的那个
}
}
return {midSum,missTwoSum-midSum};//返回缺失的两数
}
};
ps:还有一道类似的题目,可以采用异或运算的方法得到缺失的值