数组中只出现一次的两个数字-C++位运算实现-牛客BM52

一、运行结果

二、题目

 

三、思路

异或运算:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
n^0 = n;
n^n = 0;
nnm = n(nm) 满足结合律

1.我们可以让数组中的每一个数异或一下,最后会得到一个结果retall,
2.就是两个出现一次的数字的异或结果这个结果肯定是由两个不同数字异或而来,因此我们找retall二进制中为1的位置i,因为1一定是由0,1异或而来,因此要求得两个数中,一定有一个数的二进制中的第i个位置为1, 一个为0.
3.对和这个数相与为1的求异或是第一个数,为0的是第二个数

之所以让retall与其相反数相与是因为互为相反数的两个数只有一位二进制位是同时为1(并且不是符号位),而其他位相与之后必定为0(包括符号位),这里只是为了确保只选出retall中的一个为1的位,具体是哪一位不用管。对于上面的第三点做补充:出现两次的数第i位上是1或0并不影响,因为还要做异或运算,如果是出现两次的数,异或后必然为0,相与为1或为0只是为了将只出现一次的两个数分开在两个不同的子集里。

大致思路参考:https://blog.csdn.net/Fizz6018/article/details/107201709/

四、代码

class Solution {
public:
    vector<int> FindNumsAppearOnce(vector<int>& array) {
        vector<int> ans;
        int len = array.size();
        int retall = 0;  //所有的数异或的结果
        for(const int val : array){
            retall ^= val; //最终得到的是不同的两个数异或的结果,出现两次的异或后都变为0
        }
        retall &= (-retall);  //两个相反数补码必然只有一位是同时为1的(且非符号位)
        int tmp1 = 0, tmp2 = 0;
        for(const int val : array){
            if(retall & val){  //与retall相与为1得到其中一个数
                tmp1 ^= val;
            }
            else{   //得到另一个数
                tmp2 ^= val; 
            }
        }
        ans.push_back(min(tmp1, tmp2));
        ans.push_back(max(tmp1, tmp2));
        return ans;
    }
};

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值