1. 原题
一个整型数组里除了一个数字之外,其他的数字都出现了两次。请写程序找出这一个只出现一次的数字。
解题思路:利用异或操作的性质可以快速解决这个问题。
异或运算法则
a ^ 0 = a
——与 0 0 0异或等于自身;a ^ a = 0
——与自身异或等于 0 0 0;a ^ b ^ c = a ^ c ^ b
——交换律;a ^ b = c <=> a ^ c = b <=> b ^ c = a
;
代码如下,复杂度 O ( n ) O(n) O(n):
from functools import reduce
res = reduce(lambda x, y: x ^ y, array)
print(res)
2. 变体
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
变体难度与解决思路
由于这一次变成了需要找到两个思路,如果还按照原题进行异或操作,则两个不重复的数会进行异或叠加,需要将异或叠加的状态值拆解出来;根据异或运算法则4,则必须知道其中一个不重复数字才能拆解出另一个。
于是,考虑第一轮异或得到的结果res
,其二进制表示中,取得1的位,不重复数字
a
a
a和
b
b
b在该位上比不相同(根据异或运算0^1=1
得知);那么找到第一个不相同的位,根据是否与该位相同把原数列划分为两份,则分别包含
a
a
a和
b
b
b,再根据上一问中的解法进行求解即可,算法复杂度为
O
(
2
∗
n
)
O(2*n)
O(2∗n)(可以进一步优化到
O
(
3
n
2
)
O(\frac{3n}{2})
O(23n))。
def find( array):
res = reduce(lambda x, y: x ^ y, array)
# 异或结果中为1的是不重复数字a和b不同的位
index, res_store = 1, res # index取第一个遇见的1,根据此位把array划分为两组再异或
while res & 0b1 != 1:
res, index = res >> 1, index << 1
# 跟不重复数字a在index位上相同的数字列表
a = reduce(lambda x, y: x ^ y, filter(lambda x: x & index, array))
return a, a ^ res_store # 根据 a^b=c <=> a^c=b