【问题】一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
【思路】这一道题看似很简单,我们使用一个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]; } } } };