題目描述:
一個整型數組裏除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。
預備知識:
對於一個整數數組,首先我們先分析一個簡單的情況:假定數組中只有一個數據出現1次,其他數據都出現了兩次,如何找到這個只出現1次的數據?
位運算中,兩個數的異或運算規則是:二進制位相同返回0,不同返回1,由此兩個相同數據的異或值爲0,任何數據與0的異或還爲原值。如1100^1100=0000,1010^0000=1010。
所以可以很快想到,上面求唯一一個出現1次的數據就可以對數組中的數據全部異或,得到的結果就是隻出現1次的數據。
本題思路:
通過預備知識的內容,回到本題,本題的數組中由兩個只出現1次的數據,其餘數據都出現2次,設這兩個數據是A和B。
首先還是對數組中所有的數據進行異或處理,結果是A^B,我們分析一下這個結果:結果的二進制表示中,所有的0代表了A和B二進制相同的位,1代表了A和B二進制不同的位。
那麼我們就可以以A^B二進制結果中爲1的位對原數組進行劃分,例如A^B=0000100,倒數第3位爲1,遍歷原數組中所有的數據,其二進制表示中第3位爲0的劃分爲1組,第3位爲1的劃分到一組。
可以想到劃分後的這兩組,一定都是一堆出現2次的數據和1個出現1次的數據,由此就可以用預備知識中的處理方法得到結果了。
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
if(data.size()<2)
return ;
int size=data.size();
//數組中所有元素異或,結果爲兩個不同值的異或結果(同值異或結果爲0)
int temp=data[0];
for(int i=1;i<size;i++)
temp=temp^data[i];
if(temp==0)
return ;
//找到異或結果二進制表示中爲1的最低位,該位代表了原數組中不同的兩個值在此位不同
int index=0;
while((temp&1)==0){
temp=temp>>1;
++index;
}
//以上面的index位的值將原數組劃分兩組,不同的值肯定被劃分到不同的組,同值元素肯定劃分到同組
*num1=*num2=0;
for(int i=0;i<size;i++){
if(IsBit(data[i],index))
*num1^=data[i];
else
*num2^=data[i];
}
}
bool IsBit(int num,int index){
num=num>>index;
return (num&1);
}
};