描述
一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
这题用上之前说的python内置函数就是我能写出来的代码了:
class Solution:
def FindNumsAppearOnce(self , array ):
if array == []:
return False
else:
tmp = []
for i in range(len(array)):
if array.count(array[i]) == 1:
tmp.append(array[i])
return tmp
但是这道题又说清楚了只有两个数字出现一次,其他数字都出现了两次,这会不会另有玄机?
果然,讨论组又是另外一个知识点:
①如果只有一个数字仅出现一次,其余都出现两次,则所有数字异或的结果就是那个仅出现一次的数字。
什么是异或?
异或(eor)是一个数学运算符。它应用于逻辑运算。异或的数学符号为“⊕”,计算机符号为“eor”。
如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
结合律:
如果该数组中只有一个数字出现一次,就把全部数字异或,就能找到那个数。
对于有异或的题目要记住这点 每个二进制位是独立计算答案的
②讨论组题解:此题中,有两个数字只出现一次,它们与其他所有数字异或的结果一定非0,其二进制表示中一定有某一位为1,可根据这一位是否为1,将数组分为两部分。
利用二进制的第一位为1来区分两个数组,如果第一位不是1,那就判断第二位,第三位,一直到找到为1的地方。假设一直找到第n位才为1,那就判断数组中的其他数字的二进制的第n位是否为1,做&运算即可判断。
&(与)运算定义:参加运算的两个数据,按二进制位进行“与”运算。
运算规则:0&0=0 0&1=0 1&0=0 1&1=1
则两部分的所有数字分别做异或,因为异或的运算规则是可以符合结合律的,所以一旦出现两个相同的数,它们的异或结果就是0,那么那个只出现一次的数跟它们做异或的结果就是这个数本身,两部分得到的两个结果就是要求的两个结果。
class Solution:
def FindNumsAppearOnce(self , array ):
# write code here
if not array:
return []
res = 0
for i in array:
res = res ^ i
index = 0
while res & 1 == 0:
res = res >> 1
index += 1
a, b = 0, 0
for i in array:
if self.helper(i, index):
a = a ^ i
else:
b = b ^ i
return [a, b] if a < b else [b, a]
def helper(self, num, index):
num = num >> index
return num & 1 != 0
③姚青林老师的方法也很类似:
因为两个数字只出现一次,等于说把两个数字分成两边,让每一边只有一个数字只出现一次,然后取做异或。
class Solution:
def FindNumsAppearOnce(self , array ):
if len(array) < 2:
return None
twoNumXor = None
for num in array:
if twoNumXor == None:
twoNumXor = num
else:
twoNumXor = twoNumXor ^ num
count = 0
while twoNumXor % 2 == 0:
twoNumXor = twoNumXor >> 1
count += 1
mask = 1 << count
firstNum = None
secondNum = None
for num in array:
if mask & num == 0:
if firstNum == None:
firstNum = num
else:
firstNum = firstNum ^ num
else:
if secondNum == None:
secondNum =num
else:
secondNum = secondNum ^ num
return firstNum, secondNum