异或的妙用

异或 ^ ,相同为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

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

[html]  view plain copy
  1. #include<iostream>  
  2. using namespace std;  
  3. #define maxn 10  
  4. void swap(int &a,int &b)  
  5. {  
  6.     a=a^b;  
  7.     b=a^b;  
  8.     a=a^b;  
  9.     return;//现学现用  
  10. }  
  11. int main()  
  12. {  
  13.     int temp_1;  
  14.     int A[maxn]= {1,1,2,2,3,4,5,5,6,6};  
  15.     for(int i=0; i<maxn; i++)  
  16.         temp_1^=A[i];//总的异或  
  17.     int pos=1;//标记不同位  
  18.     for(int i=1; i<=8; i++)  
  19.     {  
  20.         if(temp_1&1)  
  21.         {  
  22.             pos=pos<<i-1;  
  23.             break;  
  24.         }  
  25.     }  
  26.     int L=0;  
  27.     int R=maxn-1;//用快排的方法,把序列分为两半  
  28.     do  
  29.     {  
  30.         do  
  31.         {  
  32.             L++;  
  33.         }  
  34.         while((A[L]&pos)&&L<maxn-1);  
  35.         do  
  36.         {  
  37.             R--;  
  38.         }  
  39.         while(!(A[R]&pos)&&R>0);  
  40.         if(L<R)swap(A[L],A[R]);  
  41.     }  
  42.     while(L<R);  
  43.     int temp_2=0;  
  44.     int temp_3=0;//两个子序列的异或  
  45.     for(int i=0; i<=R; i++)  
  46.     {  
  47.         temp_2^=A[i];  
  48.     }  
  49.     for(int i=L; i<maxn; i++)  
  50.     {  
  51.         temp_3^=A[i];  
  52.     }  
  53.     cout<<temp_3<<' '<<temp_2<<endl;  
  54.     return 0;  
  55. }  


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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值