CSDN话题挑战赛第2期
参赛话题:算法题解
题目链接与描述
https://leetcode.cn/problems/missing-two-lcci/
关键词:求和 原地hash 异或
第一反应又是暴力求解,排序后取两个,但是时间不满足
方法一:求和
- 利用等差公式可以得到全部1-n的和
- 遍历nums可以得到缺失2位数后的和
- 两数相减,就是我们求的两数之和sum
- sum/2,可以得到两数中间值,一个在左,一个在右
- 同理,我们可以根据等差公式得到1-sum/2的和
- 也可以求到1-sum/2 数组中的和
- 两数相减就得到了左边的数字,sum-左边数字就是右边数字了
运行截图
代码
public int[] missingTwo(int[] nums) {
int n = nums.length + 2;
long sum = 0;
for (int x: nums) sum += x;
long sumTwo = n * (n + 1) / 2 - sum;
long limits = sumTwo / 2;
sum = 0;
for (int x: nums)
if (x <= limits) sum += x; // 两个数不相同那么一个大于,一个小于
long one = limits * (limits + 1) / 2 - sum;
return new int[]{(int)one, (int)(sumTwo - one)};
}
方法二:异或
原理与求和类似,异或(相同为0,不同为1)是使用了:
- a xor a = 0
- 异或遵循算数组合(1-n的异或 1-n缺失两位的异或=两位缺失的异或):
- a xor b xor b = a
- a xor b = c 并且 a xor b xor a=c xor a,即 b = c xor a
- 然后最后得到两个缺失的异或,通过lowbit,必然是一个为1一个为0(不然就两个数相等了),再前面的两个全员异或一遍,通过分界,能够得到其中一个,再与前面的异或结果 就得到另一个
运行截图
代码
public int[] missingTwo(int[] nums) {
int n = nums.length + 2;
int xor = 0;
for (int v : nums) {
xor ^= v;
}
for (int i = 1; i <= n; ++i) {
xor ^= i;
}
int diff = xor & (-xor);
int a = 0;
for (int v : nums) {
if ((v & diff) != 0) {
a ^= v;
}
}
for (int i = 1; i <= n; ++i) {
if ((i & diff) != 0) {
a ^= i;
}
}
return new int[] {a, xor ^ a};
}
方法三:原地hash
通过数组下标和值映射,不再一个的就交换,最终遍历一遍就得到了缺失的数,这个和前面刷到的一道题解法一致
运行截图
代码
public int[] missingTwo(int[] nums) {
int[] hash = new int[nums.length+2];
for(int i = 0 ; i < nums.length;i++){
hash[nums[i]-1]++;
}
//hash记录
int[] re = new int[2];
int i = 0;
for(int j = 0 ; j < hash.length;j++){
//把0排除在外
if(hash[j] == 0){
re[i++] = j+1;
}
}
return re;
}
结尾
发现这道题的一百有点容易啊
欢迎评论区交流,每日打卡,冲冲冲!!!