1,题目要求
Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.
对于一个数组,只有两个数字是出现一次的,其他的所有的数字都是出现两次的,找出这两个数字。
2,题目思路
对于这道题,首先比较简单的方法就是直接利用unordered_map来对其中出现的数字以及他们出现的数量进行统计,最后再进行遍历找到两个只出现一次的数字即可。这种方法虽然速度不错,但是需要额外开辟很大的空间。
对于第二种方法,是找到这样单独出现的数字的一个比较常规的方法:XOR
如果只有一个只出现一次的数字就比较简单了,直接从都往后XOR一遍即可,因此0 XOR num = num,相同的数字的XOR的也为0,因此最后剩下的一定就是只出现一次的数字了。但是这道题,有两个只出现一次的数字,因此我们要分开进行处理。
首先,将所有的数字都进行XOR,最后得到的一定是两个不同的数字的XOR,这时,我们找到他们的最小的不同的比特位:
比如,对于3和5,他们进行XOR的结果是6,二进制为110,因此10就是最小的不同的比特位。之所以要找这样的比特位,就是为这样的diff可以将3和5进行区分。
XOR的运算里,相同取0不同取1,因此最小的比特位也是最小的二者不同的位。
因此,在找到这样的diff之后,就可以分开来对num进行遍历查找。
3,程序源码
方法1:使用unordered_map
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
unordered_map<int, int> count;
vector<int> res;
for(auto n : nums)
count[n]++;
for(auto c : count)
{
if(res.size() == 2) break;
if(c.second == 1) res.push_back(c.first);
}
return res;
}
};
方法2:利用XOR
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
int diff = accumulate(nums.begin(), nums.end(), 0, bit_xor<>());
diff &= -diff; //获得最后边的一位(即原数组中两个不同的数字的最右边的不同的bit位)
vector<int> res {0,0};
for(auto n : nums)
{
if((n & diff) == 0)
res[0]^=n;
else
res[1]^=n;
}
return res;
}
};
注:
accumulate函数,一般是只有三个参数,用作累加。
当然也可以像上面这样,有四个参数,第四个参数是进行的操作函数,这里是进行xor。
C++的STL中accumulate的用法