数组中只出现一次的数字(四十)
题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。
代码(已在牛客上 AC)
这道题的思路是, 先对整个数组求异或, 因为保证其他数字都出现偶数次, 而其中两个数字都只出现一次, 那么异或的结果 res
肯定不为 0, 这样的话, res
的二进制表示中肯定有为 1 的位(假设为第 k
位), 比如 res
的二进制如果为 10010
, 那么第 1 位以及第 4 位为 1. 之后遍历整个数组, 将其中的元素根据其二进制表示中的第 k
位是否为 1, 将数组中的元素分为了两组 A 和 B, 其中 A 中除了某元素 num1
只出现了一次外其他元素都出现偶数次, B 亦同理.
那么分别对子数组 A 和 B 求异或即可得到 num1
和 num2
的值.
那么现在的问题是如何判断某个数的二进制表示中的第 k
位是否为 1. 根据 res & (res - 1)
与 res
存在如下关系: 前者是由后者的二进制表示去掉最右边的 1
形成的(比如 res
为 10010
, 那么 res & (res - 1)
结果为 10000
), 这样的话, 两者的异或就是一个 mask
(比如前面的例子, 两者异或的结果为 00010
), 刚好可以用来判断第 k
位是否为 1.
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
if (data.size() < 2) return;
int res = 0;
for (auto &d : data) res ^= d; // 1. 首先求出所有元素的异或结果
int mask = ((res & (res - 1)) ^ res);
*num1 = *num2 = 0;
for (auto &d : data) { // 3. 将元素按照 idxBit 这一位是否为 1 进行分组
if (isBit1(d, mask)) *num1 ^= d; // 4. 将同一组的元素进行异或
else *num2 ^= d;
}
}
private:
bool isBit1(int num, int mask) {
return (num & mask);
}
};