题目:一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
方法:分组异或
用另一题引申。找到数组中只出现一次的数。方法是用 0 去异或所有数字,两个相同的数就会抵消为 0,最后异或得到的结果就是数组中只出现一次的数
用这种方法,我们可以应用到这题。把数组中的数分成两部分,这两部分单独包含一个只出现一次的数,就可以解决问题。
对遍历整个数组异或后的结果 k ,k 的二进制中,至少有一位为 1,那么可以用这位 1 来把两个数区分开来,通过一点点右移 1 和 k做与操作,就可以找到这个 1 了。
- 时间复杂度 O(n),遍历两次数组
- 空间复杂度 O(1)
public int[] singleNumbers(int[] nums) {
int k = 0;
// 用 k 来计算掩码 mask
for (int num : nums) {
k ^= num;
}
int mask = 1;
// while 找到最低位的 1
while ((mask & k) == 0) {
mask <<= 1; //右移 1 位
}
int a = 0, b = 0;
for (int num : nums) {
if ((num & mask) == 0) { // 不能改成 1,因为不清楚这个 1 在哪一位
a ^= num;
} else {
b ^= num;
}
}
int[] res = new int[]{a, b};
return res;
}