给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗?
以任意顺序返回这两个数字均可。
示例 1:
输入: [1]
输出: [2,3]
示例 2:
输入: [2,3]
输出: [1,4]
提示:
nums.length <= 30000
法一:位运算
class Solution { public: //数组完全可能是乱序 vector<int> missingTwo(vector<int>& nums) { vector<int> res; //法一:异或法 想办法将两个数分开,有点类似一sigleNumber的想法,有两个数落单;分出两个数组来异或 int N = nums.size()+2; int tdiff = 0; for(int i=1;i<=N;i++){ tdiff ^= i; } for(int i=0;i<nums.size();i++){ tdiff ^= nums[i]; } //diff此时是两个数的异或值,两个数不想等,利用mask标志分开两个数。 int mask = 1; while(!(mask & tdiff)){ mask = mask << 1; } //mask现在就是第一个不同的xxxx1xxxx //两部分数用mask分开 int one = 0; for(int i=0;i<nums.size();i++){ if(mask & nums[i]) one ^= nums[i]; } for(int i=1;i<=N;i++){ if(mask & i) one ^= i; } res.push_back(one); res.push_back(one^tdiff); return res; } };
法二:分组求和
class Solution { public: vector<int> missingTwo(vector<int>& nums) { vector<int> res; //法二 分组求和 int N = nums.size()+2; int sumN = 0,sumNum = 0,sumNumLess=0,sumNLess=0; for(auto num : nums) sumNum += num; for(int i=1;i<=N;i++) sumN += i; //diff是两个数的和 int sumTwo = sumN - sumNum; //求两个数和的一半,那么两个缺失得数一个大于diff,一个小于diff。 int diff = (sumTwo)/2; //针对 N 和sum两个数组,小于等diff的分别分为一组;大于diff的分别分为一组;那么两个组的差值即为缺失的一大一小 for(auto num : nums){ if(num<=diff){ sumNumLess+=num; } } for(int i=1;i<=N;i++){ if(i<=diff){ sumNLess+=i; } } res.push_back(sumNLess-sumNumLess); res.push_back(sumTwo-(sumNLess-sumNumLess)); return res; } };