给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗?
以任意顺序返回这两个数字均可。
示例 1:
输入: [1]
输出: [2,3]
示例 2:
输入: [2,3]
输出: [1,4]
提示:
nums.length <= 30000
解题思路
数学思考
因为知道1~n的所有整数,然后给出已有的n-2个数,很容易就能想到将这n-2个数异或,与1~n的异或就差了缺的俩数x = x1^x2异或值
那么重要的点来,如何利用x1^x2来分别得到x1,x2?
- Key1: 一堆已知的数中只缺一个数的话可以通过异或得到
- Key2: 利用x1和x2特征区别将数分为两类:
- 通过x&(-x)即可得到x1^x2异或值中的一个二进制第i位的1,那么这个1意味着x1和x2在该二进制位不同才会异或得到1
- 对1~n的数通过第i位值划分为两类,对nums也划分为两类
- 有了x1 和 x2分别属于两类,如此通过Key1可以找到x1,x2
代码
class Solution {
public:
vector<int> missingTwo(vector<int>& nums) {
int x = 0;
int n = nums.size()+2;
// 将1~n和nums异或起来,得到缺的两个数字异或值x=x1^x2
while(n) x ^= n, n--;
for(int i = 0; i < nums.size(); i++) x ^= nums[i];
// 找到二进制中x1 和 x2异或值为1的一个位置,说明此位置上两数不同
int flag = x&(-x); // 得到的是x1与x2异或值为1的最低位
// 找到1~n此位置为1的数异或得到一个值y1,找到nums中此位置为1的数异或得到一个值y2,这俩异或值的区别就是x1的参与,y1^y2=x1
// 同理看此位置为0的异或值,得到x2
int y1 = 0, y2 = 0;
int y3 = 0, y4 = 0;
n = nums.size()+2;
while(n){
if(n&flag) y1^=n;
else y3^=n;
n--;
}
for(int i = 0; i < nums.size(); i++){
if(nums[i]&flag) y2^=nums[i];
else y4^=nums[i];
}
return {y1^y2,y3^y4};
}
};