面试题 17.19. 消失的两个数字
给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗?
以任意顺序返回这两个数字均可。
示例 1:
输入: [1]
输出: [2,3]
示例 2:
输入: [2,3]
输出: [1,4]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/missing-two-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题
O(1)空间——位运算,数学,哈希;
解法1:位运算
可得到未缺失的数组为从1开始到nums.size()+2的数组;
故用res异或便利两个数组,得到两个缺失数的和的位值;
由此题目转化为56.数组中数字出现的个数——即从一个成对的数组中找到两个单个出现的数;
找到res里第一个为1的位(res&(-res)),这两个数在该位上不同,一个为1,一个为0,故将数组分为两类,第一类该位为1,第二类该位为0;
class Solution {
public:
vector<int> missingTwo(vector<int>& nums) {
int res=0;
for(int num:nums)
res^=num;
for(int i=1;i<=nums.size()+2;i++)
res^=i;
int f=res&(-res);
int a=0,b=0;
for(int num:nums)
if(f&num) a^=num;
else b^=num;
for(int i=1;i<=nums.size()+2;i++)
if(f&i) a^=i;
else b^=i;
return {a,b};
}
};
解法2:数学
计算两者总和,得到a+b;
计算两者各个平方综合,得到a^ 2 + b ^ 2;
由此得到a-b,继而得到a和b;
class Solution {
public:
vector<int> missingTwo(vector<int>& nums) {
long long sum=0;
long long sum1=0;
for(int num:nums)
sum+=num;
sum1=(1+nums.size()+2)*(nums.size()+2)/2;
int aplusb=sum1-sum; //得到a+b
sum=0;
sum1=0;
for(int num:nums)
sum+=num*num;
for(int i=1;i<=nums.size()+2;i++)
sum1+=i*i;
int aaplusbb=sum1-sum; //得到a^2+b^2
int ab=(aplusb*aplusb-aaplusbb)/2; //得到a*b
int acutb=sqrt(aplusb*aplusb-4*ab);
int a=(acutb+aplusb)/2;
int b=a-acutb;
vector<int> res={a,b};
return res;
}
};
解法3:哈希
往数组尾部插入3个-1,将数组大小增到n+3;
遍历数组,将nums[i]!=[i]的位置都做swap(nums[nums[i]],nums[i]),直到num[i]==-1,遍历下一个 i ;
然后遍历数组,将值为-1的入vector,输出即可;
class Solution {
public:
vector<int> missingTwo(vector<int>& nums) {
for (int i = 0; i < 3; i ++) nums.push_back(-1);
for (int i = 0; i < nums.size(); i ++)
while (i != nums[i] && nums[i] != -1)
swap(nums[i], nums[nums[i]]);
vector<int> ans;
for (int i = 1; i < nums.size(); i ++)
if (nums[i] == -1) ans.push_back(i);
return ans;
}
};