1. 题目
一个整型数组里面除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(N),空间复杂度是O(1)。
2. 思路
首先,可以想一下,如果数组中只有一个数字只出现了一次,其他数字都出现了两次,怎么找出这个数字呢?根据这个问题可以想到异或的一个性质:加任何一个数字异或它自己都等于0。也就是说,如果从头到尾异或每个数字,那么最终的结果就是那个只出现了一次的数字,因为那些成对出现的数字都在异或中抵消了。
根据上面的思路,我们异或数组中的所有数字,这里可以得到一个不为 0 的数字,这个数字是数组中两个只出现一次数字的异或结果。因为这个结果不为 0,因此我们可以从右向左找出这个数字二进制第一个不为 0 的数字,根据这一位将数组分为两个子数组(长度为 2),这一位为 1 的数字放在第一个子数组中,这一位为 0 的数字放在第二个子数组中。对这两个子数组进行异或操作,即可得到最终的结果。
3. 代码
public class F56FindNumsAppearOnce {
public void solution(int[] data,int[] result){
if(data==null || data.length<2)
return ;
int resultExclusiveOR = 0;
// 将数组中所有数字都进行异或操作
for(int i=0;i<data.length;i++)
resultExclusiveOR ^= data[i];
// 找出异或操作结果二进制第一个不为 0 的位置
int indexOf1 = findFirstBitsIs1(resultExclusiveOR);
// 根据 indexOf1 位置上是否 1 分为两个数组
for(int i=0;i<data.length;i++){
if(isBit1(data[i],indexOf1)){
result[0] ^= data[i];
}else{
result[1] ^= data[i];
}
}
}
private int findFirstBitsIs1(int num){
int index = 0 ;
while((num&1)== 0){
num>>=1;
index++;
}
return index;
}
private boolean isBit1(int num,int index){
num >>= index;
return (num&1)==1;
}
}