异或^运算——找到数组中为奇数个数的元素

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6


文章目录

  • ​​题目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,我们就可以得到

retNum = 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));
}


阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6