栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

数组中只出现一次的两个数字-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 FindNumsAppearOnce(vector& array) {
        vector 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;
    }
};

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/832879.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号