异或的应用C++(经典面试题)----你会吗

题目:
在一个数组中,只有两个不相同的数出现奇数次,其余都出现过偶数次,求找出那两个数字,要求时间复杂度为O(n),空间复杂度为O(1).

性质:
1)0^N=N   N^N=0
2)满足交换律。

思路:
1)假设那两个出现奇数次的分别为a、b,先将所有数异或到ero上,结果ero=a^b≠0,
2)然后找到ero二进制位为1的那一位,然后将数祖中数按照这一位分为两组A、B,
3)然后将A、B中数分别全部异或在一起,即为所求答案a,b。        

问题解释:
1)为什么要找那个1

比如a=3,b=5,ero=a^b
   3      011
   5      101
   ero   110
比如找最后一个1,即ero中的倒数第二位,往上看3和5对应的那一位二进制数字、分别是1和 0,所以就有了区分,就可以按照这一位分别分出两组,一组包含3在内的所有该位为1的数字,一组包含5在内的所有该位为0的数字。

2)怎样找出最后那一个1
比如 
                 ero:    10101100
               ~ero:    01010011
           ~ero+1:    01010110
 ero&(~ero+1):     00000100
那么最后那一位1就找到了。

3)怎么按照那一位分成两组呢
arr[i]&(ero&(~ero+1))==0说明那一位不是1;arr[i]&(ero&(~ero+1))!=0说明那一位是1。

代码实现:

void find(int arr[],int sz){
    int ero=0;
    for(int i=0;i<sz;i++)
        ero^=arr[i];
    int rightone=ero&(~ero+1);//提取最右的1
    int onlyone=0;
    for(int i=0;i<sz;i++){
        if(arr[i]&rightone==0)//分类
            onlyone^=arr[i];
    }
    cout<<onlyone<<" "<<ero^onlyone<<endl;//a^b^a=b
}

EOF!!!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值