【问题】一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

【思路】这一道题看似很简单,我们使用一个hashmap用来统计每个数出现的次数或者使用hashset,遍历的同时查找hashset,如果存在则删除,如果不存在就将数字存入hashset,最后hashset中只存在出现一次的两个数,但如果题目不让你是用辅助空间,即空间复杂度为O(1),怎么办?

有人就想到了异或算法,异或是指二进制中,如果两位相同则为零,不同则为1。假如有一组数据[6, 5, 6, 7, 7],我们设立初始值x=0,对这个数组进行累积的异或运算,最后等于5. 这就是一个异或运算的性质,不管两个相同的数字在那个位置,经过异或可以各自抵消!

因此题中的数组经过这个运算后最后得到的是两个数(只出现一次的)的异或值,那么怎么分开呢?
其实思路也很简单,如果两个数不同的话,那么其二进制必定有一位数不同导致其异或位为1,加入是最后一位不同,那么我们可以从头遍历并判断每个数&1,那么就会将所有的数分成两个数组,而这两个单独的数也一定会被分开,这样就成了我们第一段我们说的只包含一个孤独的数的情况,然后遍历进行异或运算就可以得到这两个数组中的孤独的数!哈哈哈,思路很棒!

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        int x = 0;
        int len = data.size();
        for(int i=0; i<len; ++i){
            x = x^data[i];
        }
        int t = x^(x-1) & x; //找1所在的最低位,这个比较简洁易懂
        *num1 = 0;
        *num2 = 0;
        for(int i=0; i<len; ++i){
            if(data[i] & t){
                *num1 ^= data[i];
            }else{
                *num2 ^= data[i];
            }
        }
    }
};