数组中数字出现的次数(位运算+自动机)

题目

在一个数组 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

可作以下状态转换图

状态转换图

0
0
0
1
1
1
10
AB
00
01

真值表

将状态图转换为真值表

CABAB
00000
00101
01010
011X
10001
10110
11000
111X

先分析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ˉ(BC)


保留A状态,先计算B状态转移,
此时状态图发生改变,不再等效

1
1
1
10
AB
00
01

当AB状态对调后,状态图恢复等效情况

1
1
1
10
BA
00
01

A变成了低位, 可以对A使用B的公式

A = B ˉ ( A ⊕ C ) A = \bar{B}(A\oplus C) A=Bˉ(AC)


代码实现

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值