解题思路
本题有很多种解法,但由于题目进行了限制,因此只能采用位运算的方法才能满足。
异或运算有以下三个性质
移位运算:>>
每右移1位,相当于除2
与运算:&
判断为奇数还是偶数
对于此题的一个简化版的题目136. 只出现一次的数字
136题可以通过一次遍历的方式直接求解。而本题由于有两个出现的数字,因此如果可以拆分成两个数组,就可以通过136题的方法进行求解。
如果从头到尾依次异或当前的数组的元素,我们的结果将是两个只出现一次的数字异或的结果,由异或的性质可知,两个数相同为0,不同为1,因此可以通过对得到的数字找它第1位为1的位置(从右到左找),并根据这个位置将数组分成两个子数组,再到两个子数组中分别遍历,就可以找到只出现一次的数字。
例如nums = [1,2,10,4,1,4,3,3]
,2和10是我们的输出,转换为2进制的形式,并进行异或
2:0010
10:1010
1000
因此可以发现通过该数字的第3位将数组进行划分
代码
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
vector<int> ans;
if (nums.size() == 0) return ans;
ans.push_back(0);
ans.push_back(0);
int num = 0;
for (auto e : nums) {//求两个不同数字异或的结果
num ^= e;
}
int indexBit = FindFirstBitIs1(num);
for (auto e : nums) {//对每个子数组进行异或
if (isBit1(e, indexBit)) ans[0] ^= e;//子数组1
else ans[1] ^= e;//子数组2
}
return ans;
}
unsigned int FindFirstBitIs1(int num) {
int indexBit = 0;
while (((num & 1) == 0)) {//和1做与运算,判断是否为1,注意这里的==运算符优先级是高于&,因此要加括号
num = num >> 1;//右移一位
indexBit++;
}
return indexBit;
}
bool isBit1(int num, unsigned int indexBit) {//判断该位是否为1
num = num >> indexBit;
return (num & 1);
}
};