比如,1,2,3,1,2,3,4,5,6。在这个数组中,456出现了一次,123出现了两次。那么我们的目的就是求出456。
首先我们可以想到的是,这个数组绝对是有奇数个元素的。
那么我们可以根据不同的bit的值【不是1就是0】,将数组分成两个数组。第一个数组该bit为1,记该数组的元素个数为count1,第二个该bit为0,记该数组的元素个数为count0。
那么,先判断count1和count0哪个是奇数。
针对奇数的那个数组,比如说是count1,另外一个数组的的所有数字异或,结果可能为0【说明所有的三个只出现一次的数字都在count1的那个数组中】,也可能不为0【说明三个只出现一次的数字有两个在本数组中】。
如果第二个数组的异或结果不为0,那么第一个数组的所有值异或起来就是一个答案,记为a,再在第二个数组中找到那两个数字就可以了。
如果第二个数组的异或结果为0,那么三个数字都在第一个数组中。继续根据其他bit来划分。
看代码:
package a;
public class CopyOfTest1 {
public static void main(String ss[]) {
get(new int[] { 4, 5, 1 });
}
public static void get(int[] d) {
int temp1 = 0;
int count1 = 0;
int temp0 = 0;
int count0 = 0;
for (int i = 0; i < 32; i++) {// 遍历32个bit
count1 = count0 = temp1 = temp0 = 0;
for (int j = 0; j < d.length; j++) {// 遍历数组
if (isON(d[j], i) == 0) {// 当前bit为0
temp0 ^= d[j];
count0++;
} else {// 当前bit为1
temp1 ^= d[j];
count1++;
}
}
if ((count1 & 0x1) == 1) {// count1是奇数个
if (temp0 == 0) {// 那么所有的三个数都在count1那边
continue;
} else {
System.out.println(temp1);// 否则count1的异或结果就是一个数字
break;
}
} else {// count0是奇数个
if (temp1 == 0) {// 那么所有的三个数都在count0这边
continue;
} else {// 否则count0就是一个数字
System.out.println(temp0);
break;
}
}
}
}
// i的第m位是否为1
static int isON(int i, int m) {
int d=1 << m;
int f=i & d;
return f;
}
}
由于三个数字是不相等的,所以针对每一个bit,必然会找到一个bit,让三个数字分裂在两个数组中。此时就能找到其中一个数字了。
那么再在另外的一个数组中找另外的两个就不是难事了。
参考了这篇文章。讲的不错,思路很好。
上面这段代码只能找到一个数字。就break了。