异或的妙用


异或 ^ ,相同为0,不同为1.通过这个性质,我们能得出许多巧妙的解决问题的办法.

 

异或的一些性质:

A^A=0;

0^A=0;

A^B^A=B;(满足交换律)

 

应用:

1.      快速判断两数是否相等

也就是用性质1,A==B?改成A^B?就行.

 

2.      不用第三个变量交换两个数

我记到这道题曾经有人考过我,当时我的方法是:

A=A+B;

B=A-B;

A=A-B;

一直以为自己的答案蛮好的.后来发现了异或版本.

A=A^B;

B=A^B;

A=A^B;

上面的式子综合一下就是:

B=A^B^B=A;

A=A^B^A^B^B=B;

完成了交换.

 

3.      特定位翻转

0^1=1;

1^1=0;

也就是任意数^1都会翻转.

利用这个性质,可以实现任意位的翻转.如:

10000101

^00001100

=10001001

实现了3,4位的翻转.

 

4.      找出非成对的数

一大串数,成双成对,只有一个落单.如果快速揪出来?

根据性质1,异或所有数,所有成双成对的都挂掉了.我们就可以在一大串数中找到落单的.

A^B^C^D^C^B^A=D.被揪出来了.

 

5.      上面问题做一个扩展,如果有两个不成对的如何,如下面序列:

A A B B C D E E.

全部异或,得到C^D.

我们再根据C^D的性质做文章

如果C^D=10000010,说明C^D的最高位不同,一个是0,一个是1.那么我们根据最高位,把原来序列划分为两段:

最高位1:A A E E C

最高位 0:B B D

答案很明显了,分别异或上面两个序列,得到C和D.

这个方法我打算编码出来.

上面方法引申到一个问题,如果快速判断某个数哪些位是1?

暂时用一个比较笨的方法,用>>遍历判断最低位.

还有一个问题,如何快速判断某个数第i位是什么?

想到了异或的一个兄弟&.

A&0=0;

11111111

&0000010

=00000010

上面的式子表示,通过&,我们可以快速找出某位的值.最后编码如下:

#include<iostream>
using namespace std;
#define maxn 10
void swap(int &a,int &b)
{
    a=a^b;
    b=a^b;
    a=a^b;
    return;//现学现用
}
int main()
{
    int temp_1;
    int A[maxn]= {1,1,2,2,3,4,5,5,6,6};
    for(int i=0; i<maxn; i++)
        temp_1^=A[i];//总的异或
    int pos=1;//标记不同位
    for(int i=1; i<=8; i++)
    {
        if(temp_1&1)
        {
            pos=pos<<i-1;
            break;
        }
    }
    int L=0;
    int R=maxn-1;//用快排的方法,把序列分为两半
    do
    {
        do
        {
            L++;
        }
        while((A[L]&pos)&&L<maxn-1);
        do
        {
            R--;
        }
        while(!(A[R]&pos)&&R>0);
        if(L<R)swap(A[L],A[R]);
    }
    while(L<R);
    int temp_2=0;
    int temp_3=0;//两个子序列的异或
    for(int i=0; i<=R; i++)
    {
        temp_2^=A[i];
    }
    for(int i=L; i<maxn; i++)
    {
        temp_3^=A[i];
    }
    cout<<temp_3<<' '<<temp_2<<endl;
    return 0;
}


6.      1到10000有10001个数,无序存放,查找两个重复数。

现在是一个重复,其他不重复.

我们只要与1-10000的所有数再异或一次,除了查找的数,其他都是偶数次异或,可以得到结果.

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值