数组中有2个不相等的数出现了奇数次,其余数出现了偶数次,如何找到这两个数。
之前练习中有过类似的题,不过是找到数组中1个出现奇数次的数,那两个数该如何找?
分析
假设两个出现奇数次数为a和b。
- 遍历数组,申请一个变量eor与数组中所有数都进行异或运算,因为相同数异或的结果为0,所以第一次异或的结果就是a ^ b,假设结果为c。
- 根据上一步得到的结果c,找到c的二进制中最右侧的1。可参考我上一篇博客看如何找到二进制中最右侧的1
- 找到c中最右侧的1(其他位置的1也可以)的位置index。说明a和b在index处是不同的(异或运算相当于无进位相加,如果此处数相同,则相加后为0)。
- 根据index可将整个数组分为两类,第一类是二进制中index处为1的数,第二类是二进制中index处为0的数。那么a和b因为不相等,并且index处不同,所以一定会在不同的分组中。
- 再次遍历数组,将数组中的每个值 & index(&:两个都是一则为一)。如果不为0,说明该元素二进制中index处不为0。又因为a、b已经明确的分为两类,所以此时可以得到其中一个的值,另一个用eor再次进行 ^ 运算,就可得到。
代码实现:
public static void findNum(int[] arr) {
int eor = 0;
for (int i = 0; i < arr.length; i++) {
eor ^= arr[i];
}
//~eor + 1 -> -eor
//找到eor中最右侧的1
int rightOne = eor & (~eor + 1);
int onlyOne = 0;
for (int i = 0; i < arr.length; i++) {
if ((arr[i] & rightOne) != 0) {
onlyOne ^= arr[i];
}
}
int otherOne = eor ^ onlyOne;
System.out.println(onlyOne + " " + onlyOne);
}