数组中只出现一次的数字

时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。


思路:

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        if(data.empty())
            return ;
        map<int,int>mp;
        vector<int> relem;
        for(int i = 0;i < data.size();i++)
        {
            mp[data[i]]++;
        }
        for(int i = 0;i < data.size();i++)
        {
            if(mp[data[i]] == 1)
            {
                relem.push_back(data[i]);
            }
        }
        *num1= relem[0];
        *num2 = relem[1];
    }
};

  • 方法二:利用位运算中异或的性质:两个相同数字异或为0,不同数异或为1(相同为0,不同为1)

当只有一个数出现一次时,我们把数组中所有的数,依次异或运算,最后剩下的就是落单的数,因为成对儿出现的都抵消了。
依照这个思路,我们来看两个数(我们假设是AB)出现一次的数组。我们首先还是先异或,剩下的数字肯定是A、B异或的结果,这个结果的二进制中的1,表现的是A和B的不同的位。我们就取第一个1所在的位数,假设是第3位,接着把原数组分成两组,分组标准是第3位是否为1。如此,相同的数肯定在一个组,因为相同数字所有位都相同,而不同的数,肯定不在一组。然后把这两个组按照最开始的思路,依次异或,剩余的两个结果就是这两个只出现一次的数字。
举个例子:

假如该数列为:1,2,1,2,3,4
第一个数与第二个数异或:001 ^ 010 = 011
上一结果与第三个数异或:011 ^ 001 = 010
上一结果与第四个数异或:010 ^ 010 = 000
上一结果与第五个数异或:000 ^ 011 = 011
上一结果与第六个数异或:011 ^ 100 = 111

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        if(data.size() < 2)
            return ;
        int size = data.size();
        int temp = data[0];
        for(int i = 1;i < size;i++)
            temp = temp ^ data[i];
        if(temp == 0)
            return ;
        int index = 0;
        while((temp & 1) == 0)
        {
            temp = temp>>1;
            index++;
        }
        *num1 = *num2 = 0;
        for(int i = 0;i < size;i++)
        {
            if(IsBit(data[i],index))
                *num1 ^= data[i];
            else
                *num2 ^= data[i];
        }
    }
    bool IsBit(int num,int index)
    {
        num = num >> index;
        return (num & 1);
    }
};

真的非常巧妙,值得多多研究
附上:按位与、或、异或等运算方法

posted @ 2020-04-01 14:03  牛犁heart  阅读(190)  评论(0编辑  收藏  举报