题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。
请写程序找出这两个只出现一次的数字。
你可以假设这两个数字一定存在。
样例:
思路1
首先想到的是使用哈希表,统计每个数字出现的频数,最后再遍历哈希表,找出只出现一次的数字。这样的时间复杂度为O(n),空间复杂度为O(n)。问题解决。实现代码如下:
思路1代码
class Solution(object):
def findNumsAppearOnce(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
dic = dict()
res = []
for i in nums:
if i in dic:
dic[i] += 1
else:
dic[i] = 1
for key, val in dic.items():
if val == 1:
res.append(key)
return res
思路2
若要求时间复杂度为O(n),空间复杂度为O(1),哈希表的方法就不能使用了。在LeetCode上,有大神提出了分组位运算的解法。
1、若数组中只存在一个只出现一次的数字,则将所有数字进行异或操作,最后的结果就是该只出现一次的数字,原因:a^b ^a = a ^ a ^ b = 0 ^ b = b(异或运算的交换律);
2、若数组中存在两个只出现一次的数字,若将所有数字进行异或操作,最后的结果为这两个数异或的结果,即 a ^ b ^ c ^ c = a ^ b;
3、若能将数组中的数分为两组,每组包含一个只出现一次的数字,相同的数分到同一组,则两组数分别进行异或操作,最后的到的数就是两个只出现一次的数。
4、但我们无法通过异或结果来获取那两个数。此时的难点在于,对两个不同数字的分组。此时我们要找到一个操作,让两个数字进行这个操作后,分为两组。最容易想到的就是 & 1 操作, 当我们对奇偶分组时,容易地想到 & 1,即用于判断最后一位二进制是否为 1来辨别奇偶。
5、通过 & 运算来判断一位数字不同即可分为两组,那么我们随便两个不同的数字至少也有一位不同吧!我们只需要找出那位不同的数字mask,即可完成分组( & mask )操作。
由于两个数异或的结果就是两个数数位不同结果的直观表现,所以我们可以通过异或后的结果去找 mask!所有的可行 mask 个数,都与异或后1的位数有关。为了操作方便,我们只去找最低位的mask。
此思路参考了:LeetCode链接 这位大神的思路。
代码实现
class Solution:
def singleNumbers(self, nums: List[int]) -> List[int]:
k = 0
for n in nums:
k ^= n
mask = 1
while((k&mask) == 0): # 找到最低位的mask
mask <<= 1
a = 0
b = 0
for n in nums:
# 利用&mask操作进行分组,统一规则下,相同的数分到同一组,不同的数分到不同组
if ((n&mask) == 0):
a ^= n
else:
b ^= n
return [a, b]