只出现一次的数字
1. 两个数字出现一次,其余数字出现两次。O(n)+O(1)。
找一个不同点,将所有数字分为两类。其中,两个只出现一次的数字各出现在一个集合当中。
如何找最后一个不同点?我们知道,如果两个数字不同的话,那么,在二进制表示下,他们一定有一个二进制位是不同的,其中一个为 0 0 0,一个为 1 1 1。通过对所有数字求异或和,就可以得到 a a a ^ b b b,然后枚举一下,任意找一个不同点即可!
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int xors = 0;
for(auto &x : nums) xors ^= x;
int diff = 0; // 二进制表示中第一个不同点
for(int i = 0; i < 32; i ++ ) {
if(xors >> i & 1) {
diff = i;
break;
}
}
int r1 = 0, r2 = 0;
for(auto &x : nums) {
if(x >> diff & 1) r1 ^= x;
else r2 ^= x;
}
return {r1, r2};
}
};
2. 一个数字出现了一次,其余都出现了三次
我们首先从暴力的角度出发,我们可以枚举每个 bit 位置 1 的数量,如果该 bit 位置 1 出现了 3 次,就消为 0,这可以通过对 3 取模实现。时间复杂度是 O ( 32 N ) O(32N) O(32N)。
class Solution {
public:
int trainingPlan(vector<int>& actions) {
int res = 0;
for(int i = 0; i < 32; i ++ ) {
int cnt = 0;
for(auto &x : actions) cnt += x >> i & 1;
cnt %= 3;
res += cnt << i;
}
return res;
}
};
那么,我们有没有办法不枚举每个 bit 位置,而是一次性直接对数字的所有 bit 位置进行位运算,将时间复杂度优化到 O ( N ) O(N) O(N) 呢?
试想一下,我们可以设计一种逻辑运算,当某个 bit 位置的 1 出现 3 次时,该逻辑运算的结果是 0,其他情况下为 1,这样我们对所有数字进行该逻辑运算,得到的结果就是那个只出现一次的数字。
在这里我们可以定义两个变量 ones
和 twos
,分别记录 bit 位 1 出现一次的位和 1 出现两次的位。注意在这里我们无需记录 1 出现了三次的 bit 位,因此在我们的逻辑运算中,出现了三次的 bit 位会计算为 0,也即出现 0 次。由于 0 比较特殊,这里我们无需显示额外记录。那么最后 ones
即为我们想要的答案。
例如,
ones=10=1010B
。其中,bit 位置为 1 和 4 的位为 1,表示这两个 bit 位 1 出现的次数为 1。另外,bit 位置为 0 和 3 的位为 1,表示这两个 bit 为 1 出现的次数为 0,它包含在 ones 中隐式表示了。
为了得到这种逻辑运算,我们可以运用数字电路中的卡诺图,一种用于简化布尔表达式的方法,它可以帮助我们直观地找出最简逻辑表达式。
通过上面的分析,这里有三种状态:[0, 1, 2],分别表示 bit 位中 1 出现的次数为 0 次,1次,2次。我们用 ones
表示 1,twos
表示 2,0 隐式表示。
我们可以将 ones
和 twos
分别视为两个二进制位的低位和高位,在接受一个新数字时,我们就可以得到 ones
和 twos
的卡诺图。
# AB分别表示twos、ones
# AB为11的结果是无意义的,用x表示
# 10在接受输入1之后变成00,表示出现3次1的bit为又化为0了
# A 的卡诺图
AB\C | 0 | 1
=================
00 | 0 | 0
01 | 0 | 1 ====> 得到 A = BC + AC'
11 | x | x
10 | 1 | 0
# B 的卡诺图
AB\C | 0 | 1
=================
00 | 0 | 1
01 | 1 | 0 ====> 得到 B = BC' + A'B'C
11 | x | x
10 | 0 | 0
class Solution {
public:
int trainingPlan(vector<int>& nums) {
int A = 0, B = 0;
for (auto &C : nums) {
int preA = A;
A = (B & C) | (A & ~C);
B = (B & ~C) | (~preA & ~B & C);
}
return B;
}
};