小学生都能看懂的题解 | #数组中只出现一次的两个数字#
数组中只出现一次的两个数字
https://www.nowcoder.com/practice/389fc1c3d3be4479a154f63f495abff8
问题描述
假设你有一堆小球,这些小球有不同的编号。现在有人告诉你,这堆小球中有两个编号是特殊的,它们只出现了一次,而其他编号的球都出现了两次。你的任务是找出这两个特殊的编号。
解决方案
我们可以用一种巧妙的方法来找出这两个特殊的编号,这种方法叫作“异或操作”。
方法步骤
- 计算所有小球编号的异或结果:
- 从第一个小球开始,用它的编号作为初始值。
- 对每一个小球的编号进行异或操作,即将新编号和当前的异或结果再做一次异或。
- 异或操作有一个特性:
- 任何数和自己异或等于0,任何数和0异或等于自己。
- 这样,那些出现两次的编号就会相互抵消掉,剩下的就是两个特殊编号的异或结果。
- 找到特殊编号异或结果中的1:
- 异或结果是一个数字,它包含了两个特殊编号的信息。
- 我们需要找到这个结果中任何一个位置上的1。
- 我们可以用一个简单的技巧来找到这个1的位置:
- 将异或结果与其负数相与(xorResult & (-xorResult))。
- 根据找到的1来区分两个特殊编号:
- 再次遍历所有小球,这次根据找到的1来区分小球:
- 如果小球的编号在找到的1的位置上有1,就放到一组。
- 如果在找到的1的位置上有0,就放到另一组。
- 对这两组小球分别做异或操作,最终得到的就是那两个特殊编号。
示例代码解释
现在我们用简单的语言来解释一下代码:
public class Solution {
/**
* 在整型数组中找出两个只出现一次的数字
* @param nums 输入的整型数组
* @return 一个包含两个只出现一次的数字的数组,按非降序排列
*/
public int[] FindNumsAppearOnce(int[] nums) {
if (nums == null || nums.length < 2) {
throw new IllegalArgumentException("Invalid input");
}
// 第一步:计算所有数字的异或结果
int xorResult = 0;
for (int num : nums) {
xorResult ^= num; // 异或操作
}
// 第二步:找到异或结果中任意一个为1的比特位
int mask = xorResult & (-xorResult); // 找到最低位的1
// 第三步:根据mask区分两个只出现一次的数字
int num1 = 0, num2 = 0;
for (int num : nums) {
if ((num & mask) != 0) { // 如果在mask的位置上有1
num1 ^= num; // 放入num1组
} else {
num2 ^= num; // 否则放入num2组
}
}
// 按非降序排列结果
if (num1 < num2) {
return new int[]{num1, num2};
} else {
return new int[]{num2, num1};
}
}
}
如果这篇文章对你有帮助,请点个免费的赞👍,让它能够帮助更多的人。
#牛客创作赏金赛#小学生都能看懂的算法 文章被收录于专栏
主要面向小白的算法文章。以小学生都能看懂为目标而编写,顺便巩固下自己。
查看14道真题和解析