集合 S 包含从1到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个元素复制了成了集合里面的另外一个元素的值,导致集合丢失了一个整数并且有一个元素重复。
给定一个数组 nums 代表了集合 S 发生错误后的结果。你的任务是首先寻找到重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。
示例 1:
输入: nums = [1,2,2,4]
输出: [2,3]
方法:排序后找到重复的元素,缺失的元素分为了两类,一类中间,一类在首尾,分别对两类获取值。
找缺失元素这里真的非常巧妙,原来是分为两种情况,一种是中间元素的缺失,不论是 12345变成11245,还是12455,缺失的部分都等于nums[i] + 1; 也就是排序后它的前面一个数加1,而当缺失的是首位的时候,测一下首尾,不是1或者最大值就把他换成最大值。
class Solution {
public:
vector<int> findErrorNums(vector<int>& nums) {
vector<int>v;
sort(nums.begin(),nums.end());
//保存重复的元素
int a=-1;
//保存缺失的元素
int b =-1;
for(int i=0; i<nums.size()-1;i++)
{
//找到重复的元素
if(nums[i]==nums[i+1])//有+1的时候就一定要考虑范围
a=nums[i];
//找到缺失的元素
if(nums[i+1]-nums[i]>1)
b=nums[i]+1;
//一旦ab被赋值之后就迅速退出循环
if(a!=-1 && b!=-1)
break;
}
//下面这两个一定要分开写!
if(a!=-1 )
{
v.push_back(a);
}
if(b!=-1 )
{
v.push_back(b);
}
//v.push_back(b);
if(v.size()<2)
{
if(nums[0]!=1)
v.push_back(1);
else
v.push_back(nums.size());//把排在末尾的数插上
}
return v;
}
};
第二种方法,这种方法简直绝了!把数学用到了极致!
class Solution:
def findErrorNums(self, nums: List[int]) -> List[int]:
S = sum(set(nums))
return [sum(nums)-S ,len(nums)*(len(nums)+1)//2-S]
用set对原容器进行排序,并去除掉重复的数字,这样,sum(nums)-S就代表了被去掉的冲重复的数字是什么!
1+2+…+n=n*(n+1)/2 这个是求和公式,那么怎么求那个缺失的元素呢?
用真正的和减去用set排序之后的和,得出来的就是原本缺失掉的那个元素!
第三种方法:
借用下面这道题的解法:
https://blog.csdn.net/weixin_45479946/article/details/108371412
class Solution {
public:
vector<int> findErrorNums(vector<int>& nums) {
vector<int>v;
//先找重复的数
set<int>s;
int n_sum=0;
int s_sum = 0;
for(int i=0; i<nums.size(); i++)
{
n_sum = n_sum+nums[i];
s.insert(nums[i]);
}
for(set<int>::iterator it=s.begin();it!=s.end(); it++)
{
s_sum=s_sum+*it;
}
int rep = n_sum - s_sum;
v.push_back(rep);
//将所有数组中的数作为下标,置对应下标的数组中的数为负数。
//被改变后的数组如果出现正数,那该正数的位置就代表未出现过得数组
//巧妙的把数组的数转换为位置
for(int i=0; i<nums.size(); i++)
{
//这里必须要加abs在nums[i]上!
//因为一轮循环之后可能就把这个值变为负数了
nums[abs(nums[i])-1] = -abs(nums[abs(nums[i])-1]);
}
for(int j=0; j<nums.size(); j++)
{
if(nums[j]>0)
v.push_back(j+1);
}
return v;
}
};