#剑指offer40数组中只出现一次的两个数字

数组中只出现一次的两个数字

https://www.nowcoder.com/practice/389fc1c3d3be4479a154f63f495abff8?tpId=13&&tqId=11193&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

剑指offer40数组中只出现一次的两个数字

剑指offer40
图片说明

1、常规方法--哈希、排序统计等
2、位运算
题解:数组所有数字异或,最终结果是要找的两个数字异或的结果,比如异或最后结果为X=0101,说明要找的两个数字a,b异或结果为0101,则a的第一位为1,b的第一位为0,即a = ###1 , b = ###0。通过这个结果,即按照第一位为1和0将数组分为两类,这样每一类中都包含若干对元素以及单独的一个a或者b,题目转化为---数组中寻找出现一次的数字,只有一个出现一次,其他出现两次。这种用位运算异或可以轻松解决
时间复杂度:O(n)
空间复杂度:O(1)
[1]:https://www.nowcoder.com/profile/396966893/codeBookDetail?submissionId=110360014
[个人代码][1]

//位运算
    //数组所有数字异或,最终结果是要找的两个数字异或的结果,比如异或最后结果为X=0101
    //说明要找的两个数字a,b异或结果为0101,则a的第一位为1,b的第一位为0,即a=***1,b=***0
    //通过这个结果,即按照第一位为1和0将数组分为两类,这样每一类中都包含若干对元素以及单独的
    //一个a或者b,题目转化为---数组中寻找出现一次的数字,只有一个出现一次,其他出现两次
    //这种用位运算异或可以轻松解决
    vector<int> FindNumsAppearOnce(vector<int>& array) {
        int ret=0; //所有元素异或结果
        for(int x:array) //所有数字异或 ret
            ret^=x;
        int mask=ret-(ret&(ret-1)); //mask为ret第一个1的位置 因为ret&ret-1消除ret的第一个1
        int index=0; //以index为界,index前面mask位是1,index后面(包括index)mask位置是0
        for(int i=0;i<array.size();i++)
        {
            if((array[i]&mask)!=0)
                swap(array[i],array[index++]);
        }
        int a=0;
        for(int i=0;i<index;i++)
        {
            a^=array[i];
        }
        int b=ret^a; //求出a后可以直接求b
        if(a<b)
            return {a,b};
        else
            return {b,a};
    }

或者如下处理也可

链接
图片说明

全部评论
两个以上也可以异或这么处理,比如:三个异或结果ret=0001,必定有个为***1,遍历一遍,所有符合***1的异或,得出第一个数a,ret2=ret^a; 为另外两个的异或,然后继续类似处理
点赞 回复 分享
发布于 2021-06-04 00:03

相关推荐

菜菜咪:1. 可以使用简历网站的模版,美观度会更好一点 2. 邮箱可以重新申请一个,或者用qq邮箱的别名,部分hr可能会不喜欢数字邮箱 3. 项目经历最好分点描述,类似的项目很多,可以参考一下别人怎么写的 4. 自我评价可加可不加,技术岗更看重技术。最后,加油,优秀士兵
点赞 评论 收藏
分享
评论
点赞
1
分享
牛客网
牛客企业服务