给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。
示例 :
输入: [1,2,1,3,2,5]
输出: [3,5]
注意:
结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。
你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?
思路:一开始想的是用暴力求解,虽然能做出来,但时间复杂度为O(N^2),超时了www,先列一下代码(其实不用列,但还是想记录一下自己的错误)
第一次的代码:
class Solution: def singleNumber(self, nums: List[int]) -> List[int]: res = [] for i in range(len(nums)): temp = 0 for j in range(len(nums)): if nums[i] == nums[j]: temp = temp + 1 if temp == 1: res.append(nums[i]) return res
转换思路:建立字典并往里面存数,数量记为1,如果遇到重复的,数量+1,最后取key值为1的数
第二次的代码:
class Solution: def singleNumber(self, nums: List[int]) -> List[int]: count = {} res = [] for num in nums: if num in count: count[num] += 1 else: count[num] = 1 for key in count: if count[key] == 1: res.append(key) return res
来一个奇葩的思路:用很神奇的XOR大法来做,题目要求是有两个数只出现一次,那么可以对他们进行一个分组,然后再用XOR去做,XOR指的是从数组第一个数开始,一直往后做异或操作,假设数组是[1,2,1,3,2],先是1^2
0x0001
0x0010 ^
—————
0x0011——>3
之后用上面得到的结果和1继续异或
然后 用上面的结果继续^1
0x0011
0x0001
————-
0x0010——>2
会发现结果变成了2,也就是说在刚才的操作中两个1互相抵消了,这样做可以说是消除了相同的数,继续做的结果得到的是3,也就是说这个数组里3只出现了一次。
不过既然题目说有两个数,那么需要对数组进行分组了,先用肉眼观察,题目样例中3和5只出现一次,那么可以对他俩进行异或操作
0x0011
0x0101 ^
————
0x0110——>6
这个表示的是3和5在二进制情况下的第二位和第三位(从右数)是不一样的,也就是说如果我们规定,第二位为0的放一组,第二位为1的放一组,就可以完美的将只出现一次的数字分开了(这个规定只是针对题目的例子)。
这时候定义一个函数lowbit,让他来求一个数出现1的最低位,例如样例中的3和5,lowbit(3,5)=2,然后判断其他数第二位是0还是1,只需要&2即可,比如说3
0x0011
0x0010 &
————
0x0010
这个第二位是1,放在第一组
再比如说1
比如1的话就是
0x0001
0x0010 &
————
0x0000
第二位是0,放在第二组
分好组之后再用XOR大法求解,完成!
奇葩思路的代码:
class Solution: def singleNumber(self, nums: List[int]) -> List[int]: res = [0, 0] xor = 0 # 求目标数二进制出现1的最低位,用来分组 def low_bit(num): return num & (-num) for num in nums: xor = xor ^ num lowbit = low_bit(xor) for num in nums: if lowbit & num == 0: res[0] = res[0] ^ num else: res[1] = res[1] ^ num return res
这个奇葩思路是一个学长提供的,他总是会给我整点新花样(逃
题目来自LeetCode第260题