题目一:求出一个数组中只有一个数出现了奇数次。
本题需要用到计算机的位运算的异或运算,即二进制位相同取0,不同取1。再结合异或的结合律、交换定律。
a != b;
a^b !=0; a^a=0
a^b^c = a^c^b;
(a^b)^c = a^(b^c)
相同数异或得到0,不同数异或不为0。出现了偶数次的数异或在一起最后得0,再异或剩下的出现奇数次的数,最后就只剩下一个数,就是出现奇数次的数。代码很简单如下:
private static int getOddNumber(int[] data) {
int res = 0;
for (int i : data) {
res^=i;
}
return res;
}
题目二:求出一个数组中有两个数ab出现了奇数次。
- 同样把所有数异或起来,偶数次的数异或在一起就得到0,剩下的异或在一起就是 a ^ b。
- a != b => a^b != 0,那么a^b一定存在一个二进制位为1,a b在这个二进制位要么一个为0,要么一个为1。所以根据这个二进制位分为两类:一类为1,一类为0,ab在不同一侧。
- 将这个二进制位的数&当前数为1数异或起来,偶数次的数异或结果为0,最后得到的要么是a要么是b。
private static void getOddNumbers(int[] data) {
//eor != 0 ,一定存在一个二进制位为1
int eor = 0;
for (int d: data) {
eor^=d;
}
//提取最右边1
int rightOne = eor & (~eor + 1);
int onlyOne = 0;
for (int cur: data) {
if ((rightOne & cur) == 1) {
onlyOne^=cur;
}
}
System.out.println(onlyOne + " " + (onlyOne ^ eor));
}