求列表中一种出现奇数次的数据
根据异或可以简单的求出
l1 = [11, 22, 33, 22, 11, 11, 11, 22, 22]
a = 0
for i in l1:
a ^ i
print(a) # 33
# 异或的功能
"""
0 ^ 任何数据 = 任何数据
相同数据 ^ 相同数据 = 0
1 ^ 0 = 1
2 ^ 0 = 2
1 ^ 1 = 0
多个数同时异或
1 ^ 2 ^ 1
异或也可以互相交换位置,上述就等于
1 ^ 1 ^ 2
0 ^ 2
2
"""
# 所以 上述的代码可以看做
"""
0 ^ 11 ^ 22 ^ 33 ^ 22 ^ 11 ^ 11 ^ 11 ^ 22 ^ 22
0 ^ 11 ^ 11 ^ 11 ^ 11 ^ 22 ^ 22 ^ 22 ^ 22 ^ 33
0 ^ 0 ^ 0 ^ 0 ^ 0 ^ 33
0 ^ 33
33
"""
求列表中两种出现奇数次的数据
异或的使用以及编码层面的操作
l1 = [1, 2, 1, 2, 2, 3, 4, 4, 5, 6, 6, 5]
a, b = 0, 0
for i in l1:
a ^= i
# 若l1中有两个出现奇数次的数据 那么 a 最终等于 数据1 ^ 数据2
# 两个不同数据的异或 结果 必定不为0 所以二进制层面 至少有一位是1 全为0才是0
# 既 设a: XXX1XXXX 这个1的位置不一定 数量也不一定 所以要通过二进制层面的操作求出最右边的1的位置
# 假若 a: 01010010 那么可以通过取反 + 1的方法 得到 a`:10101110
# 在通过 & 方法 求得 a & a` = 00000010 得到了最右边1的位置
right_one = a & (~a + 1)
# 还记得 异或 的结果吗 这个位置为1 说明 两个奇数在这个位置上 一个为0 一个为1 所以可以将所有数据分为两组
# 一组为 这个位置上是 0 一组为这个位置上为 1
# 再使用 right_one 去与所有数据 & 可以划分出 这个位置为1的数 和这个位置不为1的数
for i in l1:
if right_one & i == 0: # 这里也可以写成 right_one & i != right_one
# 在用 b ^ 这个数 就可以获得该组出现奇数次的数据
b ^= i
# 最终 b 得到了 该位置上不为1并只出现奇数次的数据
# 通过 a ^ b 就可以得到另一个了
print(b, a ^ b)
# 运行结果
# 2 3