异或^运算——找到数组中为奇数个数的元素
原创
©著作权归作者所有:来自51CTO博客作者wx63c373b99113d的原创作品,请联系作者获取转载授权,否则将追究法律责任
文章目录
- 题目1(出现奇数次的元素只有一个)
- 题目2(出现奇数次的元素有两个)
题目1(出现奇数次的元素只有一个)
给出指定数组中,查找数组中为奇数个的元素(这样的元素只有一个,其余均为偶数)
arrs = {1,1,5,2,7,5,2,5,7}
这里同样可以借助异或^的特性:相同为0,不同为1。也可以理解为,与0异或就是其本身,与自己异或为0
即代码可以写成
int retNum
for (int arr : arrs) {
retNum ^= arr;
}
即下面的逻辑可以表示为
retNum
= 1^1^5^2^7^5^2^5^7
= 1^1^2^2^5^5^5^7^7
= (1^1)^(2^2)^(5^5)^5^(7^7)
= 0^0^0^5^0
= 5
题目2(出现奇数次的元素有两个)
给出指定数组中,查找数组中为奇数个的元素(这样的元素有两个,且互不相等,其余均为偶数)
arrs = {1,1,5,2,7,5,2,5,7,7}
假设这两个数字分别为a和b,我们就可以得到
既然a不等于b,那么自然a和b的某一位一定不相同,我假设这个位置为x。
x = retNum & (~retNum + 1);
即在整个arrs数组的所有数中,x位为1的次数(0也同样开)中一定包含a或者b其中一个,该步只是为了将arrs数组中的a和b分。将包含a的这部分数据进行异或运算。如果两个数相同,其x位置的数字也相同,即异或后就会剩下a或者b
我们假设剩下的是a,就能得到下面的结果
retNum2 = a
次数得到b只需要将retNum和retNum2再次进行异或就可以了
b = retNum ^ retNum2 = a^b^a = (a^a)^b = 0^b = b
此时就可以得到出现奇数次的两个数据
最后代码合起来如下:
public static void printTwoNum(int[] arr) {
int retNum = 0,
int retNum2 = 0;
// 1、获取a^b的结果
for (int arr : arrs) {
retNum ^= arr;
}
// 2、找到a和b从右往左第一次出现不相同的二进制位下表
int x = retNum & (~retNum + 1);
for (int arr : arrs) {
// 3、a和b在x位置上,必然是一个是1,一个是0,该方法就能将a和b分开
if ((arr & x) != 1) {
// 4、将ab区分开后,再次异或,最后得到的结果就一定是被孤单出来的一个数据(整个类比题目1的概念)
retNum2 ^= arr;
}
}
// retNum2 = a或者b
// retNum ^ retNum2 = 异或一下就是另一个数据
System.out.println(retNum2 + " " + (retNum ^ retNum2));
}