题目一:数组中数字只出现一次的两个数字。
一个整形数组里除两个数字之外,其它数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度为O(n),空间复杂度是O(1)。
解题思路:位运算中异或运算的性质:两个相同数字等于0,一个数和零异或还是它本身。当只有一个数出现一次时,我们把数组中所有的数依次异或,最后剩下的数就是落单的数,因为成对的数已经抵消了。依照这个思路,在一个数组中只有两个数(A,B)出现了一次,依次异或数组中的数,则得到的结果就是A,B异或的结果。这个结果的二进制中1表示的时A,B中的不同的位,我们就去第一个1所在的位数,假设时第三位,接着把原数组分成两组,分组标准是第三位是否为1。因此相同的数肯定在一组,相同数字对应的位都相同,不同的数,肯定不在一组。然后按照一个数组中只有一个数字出现一次的方法分别找出。
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public class Solution {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
if(array == null || array.length <2)
return;
int len = array.length;
if(len == 2){
num1[0] = array[0];
num2[0] = array[1];
}
//先确定数组依次异或的结果
int result = 0;
for(int i=0; i<len; i++){
result^=array[i];
}
//我们利用异或的结果的第一个1所在的位数,作为把两个只出现一次的两个数分开
//找出异或结果的二进制为中第一个1所在的位数
int index = First1(result);
for(int i=0; i<len; i++){
if(isBit1(array[i],index)){
num1[0] ^= array[i];
}else{
num2[0] ^= array[i];
}
}
}
public boolean isBit1(int target,int index){
if(((target >> index) & 1) == 1 )
return true;
return false;
}
public int First1(int result){
int index = 0;
while((result & 1) == 0 && (index<32)){
result >>= 1;
index++;
}
return index;
}
}