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

Posted 默辨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异或^运算——找到数组中为奇数个数的元素相关的知识,希望对你有一定的参考价值。

文章目录

题目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));

以上是关于异或^运算——找到数组中为奇数个数的元素的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode Algorithm 540. 有序数组中的单一元素

LeetCode Algorithm 540. 有序数组中的单一元素

算法:异或运算^

算法异或 偶数数组中找到一个唯一奇数

ShareCode不错的技术文章 -- 如何使用异或(XOR)运算找到数组中缺失的数?

位运算