问题
思路
可参考这个链接[数组中只出现1次的两个数字(百度面试题)]。下面是我自己的总结:
首先,对于只有一个不同的数字的情形。xor可以解决。但是对于本题,由于出现两个只出现一次的数字。所以,xor的结果是最后这两个数字的xor结果。所以,直接这么做不可以。
不妨这么考虑,由于a和b是出现在同一个数组中。所以没法分开,如果把它们分到不同的数组中,对于这两个不同的数组而言。a和b是可以分别找到的。由于a不等于b,所以它们两的位向量中必然有一位不同。假设第 ci位 不同,可以利用第 ci 位与a和b相与的结果把a,b分开。同理,用 ci 位把数组中剩余的数也分开。这样对于这两个数组,分别做xor即可得到这两个数字。
大体流程如下:
- 把数组分别为各自包含a,b的两个子数组
- 对这两个子数组求xor分别获得a,b
第一个是核心,怎么划分开。上面说道,利用a和b位向量当中不同的那一位 ci 当做mask。把数组划分开即可。问题是怎么得到mask。mask是位向量当中不同的那一位,那么a^b的结果当中位向量为1的就是二者不同的位。而a^b的结果刚好可以通过对数组xor来得到。
代码
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
vector<int> v1;
vector<int> v2;
vector<int> res;
int sz = nums.size();
int ret = 0; // a^b
for( int i = 0; i < sz; ++i ){
ret ^= nums[i];
}
// debug
//std::cout << "ret=" << ret << std::endl;
int mask = 1;
while( !(ret&mask) )
{
mask <<= 1;
}
// debug
//std::cout << "mask=" << mask << std::endl;
for( int i = 0; i < sz; ++i ){
if( nums[i] & mask )
v1.push_back(nums[i]);
else
v2.push_back( nums[i] );
}
int ans1 = singleNumberOne(v1);
int ans2 = singleNumberOne(v2);
res.push_back(ans1);
res.push_back(ans2);
return res;
}
private:
int singleNumberOne( vector<int>& nums ){
int sz = nums.size();
int ret = 0;
for( int i = 0; i < sz; ++i ){
ret ^= nums[i];
}
return ret;
}
};