题目
在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
来源: 剑指 Offer 56 - II. 数组中数字出现的次数 II
分析
观察题意,注意到在二进制模式下, 对于3的倍数,每位出现次数总为三的倍数。
那么我们只需要累计每位出现"1"的次数再模三就是所得的二进制串就是本问题的解了。
有三种状态( 2 1 < 3 < 2 2 2^1 < 3 < 2^2 21<3<22), 需要用2位表示
- n % 3 = 0, AB = 00
- n % 3 = 1, AB = 01
- n % 3 = 2, AB = 10
可作以下状态转换图
状态转换图
真值表
将状态图转换为真值表
C | A | B | AB |
---|---|---|---|
0 | 0 | 0 | 00 |
0 | 0 | 1 | 01 |
0 | 1 | 0 | 10 |
0 | 1 | 1 | |
1 | 0 | 0 | 01 |
1 | 0 | 1 | 10 |
1 | 1 | 0 | 00 |
1 | 1 | 1 |
先分析B,注意观察B为1时的条件
B = C ˉ A ˉ B + C A ˉ B ˉ = A ˉ ( B ⊕ C ) B = \bar{C}\bar{A}B + C\bar{A}\bar{B} = \bar{A}(B\oplus C) B=CˉAˉB+CAˉBˉ=Aˉ(B⊕C)
保留A状态,先计算B状态转移,
此时状态图发生改变,不再等效
当AB状态对调后,状态图恢复等效情况
A变成了低位, 可以对A使用B的公式
A = B ˉ ( A ⊕ C ) A = \bar{B}(A\oplus C) A=Bˉ(A⊕C)
代码实现
def singleNumber(nums: List[int]) -> int:
A, B = 0, 0
for C in nums:
B = B ^ C & ~A
A = A ^ C & ~B
# 只有低位B才会显示0和1, A只显示0
return B