一.题目描述
Nc75数组中只出现一次的两个数字
题目链接:
https://www.nowcoder.com/practice/389fc1c3d3be4479a154f63f495abff8?tpId=188&&tqId=38602&rp=1&ru=/activity/oj&qru=/ta/job-code-high-week/question-ranking
一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
二.算法(暴力模拟)
要找到数组中只出现一次的两个数字,最容易想到的就是对整个数组进行遍历,然后找出两个只出现一次的数字。
利用c++sTL中的map可以很好的解决这个问题,下面是完整代码:

class Solution {
public:
    vector<int> FindNumsAppearOnce(vector<int>& array) {
        map<int,int>mp;
        for(int i=0;i<array.size();i++){
            mp[array[i]]++;
        }
        vector<int>q;//返回最后的两个数字
        for(auto &i:mp){
            if(i.second==1){
                q.push_back(i.first);/要是只出现一次 那就入队
            }
        }
        sort(q.begin(),q.end());//对返回的数组进行排序
        return q;
    }
};

时间复杂度:o(n)
空间复杂度:o(n*n)需要额外开辟空间返回结果和记录出现次数
优缺点:时间复杂度高,但是便于实现。

三.算法(位运算)
图片说明
如上面例子中的数组,我们每做一次异或运算,最后的1会被消去,只剩下4和6的异或结果xor。
然后我们再找这个xor的最后一个1的位置:xor-xor&(xor-1)
因为根据题目要求有两个数是不重复的,所以最后一个1的位置说明这两个数在这个位置上的二进制的数字是不同的,我们可以根据这个特性给它们分别存放在容量为2的数组的不同的位置中。得到最后的1这个数字之后,用这个数再次与整个数组进行异或运算,重复的数会被消去,只剩下那个唯一的值就是结果。下面给出完整代码:

class Solution {
public:

    vector<int> FindNumsAppearOnce(vector<int>& array) {
        int x=array[0];
        for(int i=1;i<array.size();i++){
            x^=array[i];
        }
        //找到二进制中最右边的1
        x-=x&(x-1);
        vector<int>q;
        //提前放入两个数据 防止段错误
        q.push_back(0);
        q.push_back(0);
        for(int i=0;i<array.size();i++){
            //根据他们是1还是0 来分配在数组q中的位置
            if((x&array[i])==0) q[0]^=array[i];
            else q[1]^=array[i];
        }
        //排序
        sort(q.begin(),q.end());
        return q;
    }
};

时间复杂度:o(n)
空间复杂度:o(n) 需要额外空间来存在返回结果
优缺点:空间利用率低,但是实现起来复杂