题目描述与解析:
这道题对我来说很难,根本就没有思路。所以我就仔细看了大佬发的题解,害怕以后忘记就写了这一篇博客,算是做的笔记吧。
位运算
例子: nums = [ 1, 2, 1, 3, 2, 5 ]
第一步:
先将所有的数异或(相同为0,不同为1,满足交换律),因为只有两个元素只出现一次,其余均出现两次。那么出现两次的数异或后就变成了0,最后就剩两个不同的数异或
第二步:
观察发现,异或后的第一次出现1的位置,在只相同一次的两个数中,在这位置不是0就是1.只要这个二进制位的1,别问为什么,我不知道(多观察)。最后你会求得
0010
第三步:
你在用第二步得到的值与例子中的值挨个与运算。
你会发现变成两组的数据。有一组数据进行与运算后变成了0。所以用代码怎么实现呢?
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
int val = 0;
for(auto& n1:nums)
{
val ^= n1;
}
// 0000 0101
// 0000 0011
// 异或后
// 0000 0110 -> val
int i = 0;
// val二进制第一次出现1的位置 i
// 原只相同一次的两个数,在这位置不是0就是1.
for(;i<32;i++)
{
if(val & (1<<i)) // (1<<i) -> 0000 0010
{
break;
}
}
int num1 = 0;
int num2 = 0;
for(auto& n2 : nums)
{
// 分组的思想
if(((1<<i) & n2) == 0)
{
num1 ^= n2; // 1 1 5
}else{
num2 ^= n2; // 2 3 2
}
}
vector <int> v;
v.push_back(num1);
v.push_back(num2);
return v;
}
};