题目地址:
https://leetcode.com/problems/single-number-iii/
给定一个长 n n n数组,其中除了两个数之外其余的数都恰好出现了两次,那两个数各自出现一次。将那两个数求出来。
这是一道位运算的题目。由于32位整数与异或运算构成了一个阿贝尔群(具体参见https://blog.csdn.net/qq_46105170/article/details/104082406,这里不展开了),于是我们有了这样的思路:
假设这个数组中只出现一次的数是
a
a
a和
b
b
b。我们先对整个数组所有的数异或一遍,所得结果即是
c
=
a
∧
b
c=a\wedge b
c=a∧b。由于
a
≠
b
a\neq b
a=b,所以
c
c
c必然有一位非
0
0
0,不妨把它的lowbit取出来,设为
l
l
l。这样数组中所有的数就被分成了两类,一类与
l
l
l做与运算是
0
0
0,另一类与
l
l
l做与运算非
0
0
0。不妨假设
a
a
a的lowbit等于
c
c
c的lowbit(即
a
&
l
≠
0
a\& l\ne 0
a&l=0),那么所有与
l
l
l做异或运算非
0
0
0的数,与
c
c
c再做与运算的时候,结果就是
a
∧
c
=
a
∧
a
∧
b
=
b
a\wedge c=a\wedge a \wedge b=b
a∧c=a∧a∧b=b(除了
a
a
a以外的数都成对出现,消掉了,只有
a
a
a是单独的一个,它与
c
c
c再做异或运算就把
c
c
c里的
a
a
a也消掉了)。同理可以把
b
b
b也给筛出来。代码如下:
class Solution {
public:
#define lowbit(x) ((x) & (-x))
vector<int> singleNumber(vector<int>& nums) {
int cur = 0;
for (int x : nums) cur ^= x;
int n1 = cur, n2 = cur;
int lowb = lowbit((long)cur);
for (int x : nums) (lowb & x) ? n1 ^= x : n2 ^= x;
return {n1, n2};
}
};
时间复杂度 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)。