问题描述
给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗?
解题算法
法一:位运算
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;
}
};
法三:数学运算
void FindMissingNumbers(int arr[], int n, int& num1, int& num2)
{
int sum = 0;
int squareSum = 0;
for(int i = 0; i < n; ++i){ // 这里写的有点瑕疵,应该是"i<n-2"
sum += arr[i]; // 计算剩下n-2个数之和
squareSum += arr[i] * arr[i]; // 计算剩下n-2个数的平方和
}
int expectedSum = (1 + n) * n / 2; // 计算1~n之和
int expectedSquareSum = n * (n + 1) * (2 * n + 1) / 6; // 计算1~n的平方和
// 假设缺失的两个数为a, b
int aPlusB = expectedSum - sum; // a+b = expectedSum - sum
int asqPlusBsq = expectedSquareSum - squareSum; // a²+b² = expectedSquareSum - squareSum
int aMulB = (aPlusB * aPlusB - asqPlusBsq) / 2; // a*b = [(a+b)² - (a²+b²)] / 2
int t = sqrt((double)aPlusB * aPlusB - 4 * aMulB); // t = sqrt[(a+b)² - 4*a*b] = (a-b)
num1 = (int)(aPlusB - t) / 2; // num1 = (a + b - t) / 2 = b
num2 = (int)(aPlusB + t) / 2; // num2 = (a + b + t) / 2 = a
}