https://mp.csdn.net/mp_blog/creation/editor
思路就是:
1.两个相同的数异或的结果是0
2.0跟任何数异或的结果都是0
3.这个数组中,有两个数是只出现一次,我们对这个数组所有数进行异或,相同的数都抵消,最后异或的结果就是只出现一次的两个数
4.我们得到这个ret结果,但是如何根据这个结果去得到原本的两个数???
5.假设这个ret的某一位上是1,那么这个数组里肯定分成两个组(一个组是这个位上是0,一个组这个位上是1,并且相同的数据在同一组)
比如这一位是第一位,1 的第一位就是1 ,此时两个1都在同一组,那么两个 2 就在另一组
最重要的一点是:这两个数既然只出现一次,说明他们两个不在同一组,然后他们两个互相所在的组存在相同的数据,那么我们就去判断数组中这一位是1的那一组与0去异或得到最后的数就是其中一个
另外一个也是如此.
6.有两个小细节:
第一:((flg << i) & ret) != 0 这里当时我写的是 == 1,但是错了 我没有理解 & 的概念
如果你写 == 1,是对这个 & 的总结果判断大小,实际上我们判断的是那一位是不是1,
假设 0001 & 0110 (遇0则0) 此时假设我们判断第二位, 0110 & 0010 此时 结果就是0010
说明这个总结果不是0,意味着他这个位肯定是1,如果总结果是0,其余位本来就通过按位与变成了0,这一位恰好又是0,这个时候就是0
所以你不能写 == 1,应该时候 != 0,保证你这个数结果不是0,说明这个位肯定是1啊
7.flg = flg << i
这个为什么还要执行,因为你之前只是让flg左移i然后 & ret的结果去判断,如果满足的话,flg实际上并没有改变,你还需要去手动让他左移保证flg是左移后的结果
最后你再去判断(array[j] & flg) == 0 来进行分组
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public class Solution {
public void FindNumsAppearOnce(int [] array, int num1[], int num2[]) {
if (array == null || num1 == null || num2 == null) {
return;
}
num1[0] = 0;
num2[0] = 0;
int ret = array[0];
for (int i = 1; i < array.length; i++) {
ret ^= array[i];
}
//此时得到了那两个只出现一次的数异或的结果
int size = Integer.SIZE;
int flg = 1;
int i = 0;
while (size >= 0) {
size--;
if (((flg << i) & ret) != 0) {
flg = flg << i;
break;
}
i++;
}
for (int j = 0; j < array.length; j++) {
if ((array[j] & flg) == 0) {
num1[0] ^= array[j];
} else {
num2[0] ^= array[j];
}
}
}
}