左神算法班笔记——异或

异或

异或即相同为0,不同为1(也可以看作无进位的二进制加法

0^0==0;
0^1==1;
1^0==1;
1^1==1;

异或特点:

1.满足交换律:a^b^c==a^c^b;
2.0^a==a;
3.a^a==0;
例题

现在有一个数组a,

(1)里面有1种数出现了奇数次,其他数都出现了偶数次,求这个出现了奇数次的数。

解题思路

由异或的性质可知,
同一种数自己异或自己偶数次,结果是0;
同一种数自己异或自己奇数次,结果是还是它自己。
所以,我们可以把这个数组中所有的数都异或到一起,
出现了偶数次的数异或后为0,出现的奇数次的数异或后是它自己,
这样结果就是那个出现了奇数次的数。

代码:

public static void printOddTimeNum1(int[] arr) {
        int eor = 0;
        for(int cur : arr) {
            eor ^= cur;
        }
        System.out.println(eor);
    }

(2)里面有2种数出现了奇数次,其他数都出现了偶数次,求这2个出现了奇数次的数。

解题思路:

因为是2种数,所以a^b != 0而且 a^b 必有一个二进制位上是1。
所以,我们把这个数组分为该位 是1 和 是0 两组数,
然后所有该位是1的数异或到一起,结果就是a或b其中一个。(因为其他数的出现的次数为偶数)
将该结果再与a^b异或,就能得到另一个数。

代码:

public static void printOddTimeNum2(int[] arr) {
        int eor = 0,onlyOne = 0;
        for (int curNum : arr) {
            eor ^= curNum;
        }
        // eor = a^b
        // eor != 0
        // eor的二进制必有一个位是1(因为a != b,所以必有一位不同)
        int rightOne = eor & (~eor + 1);//取出eor最右边的1
        for(int cur : arr) {
            if((cur & rightOne)==0) {//只和那一位不是1的那一类数异或
                onlyOne ^= cur;
            }
            //onlyOne 为a或b其中一个;onlyOne^eor为另一个
        }
        System.out.println(onlyOne+" "+(onlyOne^eor));
    }

代码具体解析:

int rightOne = eor & (~eor + 1);

rightOne 的唯一一位1与a^b最右边的第一个1位置相同,而且rightOne的其他位都是0

原理:(假设a^b为110010100)

a^b     		110010100
~a^b    		001101011//取反
~a^b+1  		001101100//加1
(a^b)&(~a^b+1)  000000100// 这就是rightOne

/

for(int cur : arr) {
            if((cur & rightOne)==0) {
                onlyOne ^= cur;
            }
            //onlyOne 为a或b其中一个;onlyOne^eor为另一个
        }
这样,和rightOne进行&操作后结果 为0 的数是一类,结果 不为0 的数是一类,
而a、b分别在这两类中的一类。
所以我们把同一类中的数异或到一起,就能求出a或b。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值