利用异或操作的例题,兼如何获得一个数在二进制下只保留最右边的一的形式的方法

例1:在一个数组里面存在1个只出现奇数次的数,其他数均出现了偶数次,请找出这1个只出现奇数次的数。

分析:

        题目中两种数据的区别在于出现的次数为奇数或是偶数,我们应该利用这一点来解题。

       我们知道 ^ (异或)运算的特点有:

                        1. 0 ^ a = a, a ^ a = 0

                        2. ( a ^ b ) ^ c = a ^ ( b ^ c ),  a ^ b = b ^ a

                        3. 同一组数据只要进行 ^ , 结果相同

        现如果对数组内的所有数进行异或操作,那出现偶数次的数均会因 a ^ a = 0, 而变为 0,最后只会剩下 0 ^ 我们寻找的数。

代码实现: 

int eor = 0;
for(int i = 0; i < arr_len; i++)
{
    eor = eor ^ a[i];
}

  eor即为我们搜寻的那个数

例2:在一个数组里面存在2个只出现奇数次的数(两个数不同),其他数均出现了偶数次,请找出这2个只出现奇数次的数。

分析:

        设所求两个数分别为a, b, 按例1操作,设eor,并对数组全部元素进行异或操作,得到         eor = a ^ b , 如何分离出 a , b ,就是我们面临的问题 。

        因为 a, b 为不同的数,所以eor = a ^ b 不为 0,即eor的二进制表示中必存在1,并且我们由  ^ (异或)的原理可知a,b 在存在的1位置上一个为0,一个为1,为了便于区分我们只取eor在二进制下的最后一个1作为参照,并令 a的该位置为1,b的该位置为0。并且因为已知 eor = a ^ b 的值,我们只需求出a 或 b 的值便可计算出另一个的值,我们不妨先求a的值。

        对于a,其x位置上为1,我们将数列中所有x位置上为1的数进行 ^ (异或)操作,因为符合要求的数除了a以外的所有数均为偶数个,所以异或操作后的结果为 a。我们便求得a,继而可以求得b。

int eor = 0;
for(int i = 0; i< arr_len; i++){
    eor ^= arr[i];
}
//eor = a ^ b
//eor != 0
//eor 必然有一个位置上是1

int rightOne = eor & (~eor + 1); //提取出最右边的1
int onlyOne = 0;//eor',相当于新建一个eor用以储存第二次异或的结果a的值
for(int i = 0; i < arr_len; i++){
    if((arr[i] & rightOne) == 1){
        onlyOne ^= arr[i];
    }
}//对x位置为1的所有数进行异或操作,计算出a
//a = onlyOne
//b = eor ^ onlyOne

此例中可以总结出:

如何获得一个数在二进制下只保留最右边的一的形式

//如何获得只保留一个数在二进制下最右边的1,其余位均为0的形式
//a为我们所用的数
int rightOne = a & (~a + 1); // 只保留最右边的1,其余位置均为0

  图解

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值