一个整形数组中,除了两个数外,其他每个数都出现2次,找出只出现了一次的那两个数?
分析:一般用异或的方法来去掉重复出现的数,两个相同的数进行异或运算后等于0,并且异或操作满足交换律和结合律。
如果一个数组中只有一个数字单独出现过一次,其他数字都分别出现过两次,那么用0异或数组中每一个元素就可以得到唯一出现过一次那个元素。
思路:把整个数组分为两部分,每个部分都包含一个只出现过一次的元素和若干对重复元素,分别求出这两个子数组中的唯一元素即可。
1. 首先用0依次异或数组中每一个元素,因为相同的元素异或得到0,所以最终的答案就等于那2个唯一的元素a^b的值。
2. 因为a,b不同,所以异或得到的答案肯定是不等于0的,那么我们就找到a^b的二进制表示中第一个为1的位,假如是第k位。而a,b两个数在第k位上是不同的,一个为0,一个为1
3. 接下来我们将第k位是1的分成一组,第k位是0的分成一组,如果2个元素相同,那么他们第k位肯定是一样的,所以肯定被分到同一组中。而a,b则被分到2组中去了。
然后我们就可以在每个分组中异或每一个元素,最终就可以得到那2个唯一的元素。
java代码如下:
/**
* 得到num的二进制数中第一个为1的位的位置的函数
* @param num
* @return 二进制数中1出现的最低位的位置
*/
public static int getFirstOnePos(int num){
int pos = 1;
//找到num的二进制数中第一个为1的位的位置
while((num&0x01)==0){
num = num>>1;
pos++;
}
return pos;
}
/**
* 用来分组的函数
* 如果地pos位为1,那么返回true。
* @param num 要进行分组的数
* @param pos 位置
* @return
*/
public static boolean divide(int num,int pos){
num = num>>(pos-1);
return (num&0x01)==1?true:false;
}
/**
* 查找出数组中两个只出现过一次的数
* @param a 要查找的数组
* @param n 数组长度
*/
public static void find(int[] a,int n){
int num1 = 0;
int num2 = 0;
int povit = 0;
//0异或数组中每一个元素,得到那两个只出现过一次的元素的异或值
for(int i=0;i<n;i++){
povit ^= a[i];
}
//找到a^b的二进制表示中第一个为1的位置
int pos = getFirstOnePos(povit);
for(int i=0; i<n; i++){
//分组
//第一组是pos位为1的
if(divide(a[i],pos)){
//用异或求出改组中唯一出现过一次数
num1 ^= a[i];
} else{ //第二组是pos位为0的
num2 ^= a[i];
}
}
System.out.println(num1);
System.out.println(num2);
}