求解数组中唯一出现奇数次的数,很简单。直接 xor 整个数组,偶数次xor为0,只剩下出现奇数次的数的xor。

基于此,假设数组中两个出现奇数次的数为a, b. 对数组xor结果为R,则R = a ^b. 更进一步,R二进制中的每一个1必定只出现在a或b中!

试想如果我们单独考虑R二进制最低位1(具体的十进制值并不关心),然后将数组划分成两个集合,一个集合中的数该位为1,另一个集合该位为0.试想a和b必定不在相同的集合中!且每个集合中只包含一个出现奇数次的数!然后对每个集合xor即可分别得到num1和num2!

求解整数最低位1可使用补码的技巧: low_bit = x ~ -x-x 是对二进制 x 取反加1,加1会递推原本 x 在最低位1后面的0,直到恢复 x 最低位1.

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        int x = 0;
        for (auto v: data) x ^= v;
        int low_bit = x & -x;
        for (auto v: data) {
            if (v & low_bit) *num1 ^= v;
            else *num2 ^= v;
        }
    }
};