题目描述
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
解题思路1: Map法
遍历数组, 将把元素作为key, 元素出现的次数作为val构造map. 然后在遍历map, 那个元素出现了一次并返回
示例代码:
def singleNumber2(self, nums: List[int]) -> int:
map = {}
for n in nums:
if n not in map:
map[n] = 1
else:
map[n] = map[n] + 1
for key, val in map.items():
if val == 1:
return key
return 0
解题思路2: 位运算法, 来自K神题解
- 在前边的题目中, 我们使用位运算解答过, "出了一个元素出现一次外, 其他元素都出现2次"的题目. 2.
- 使用^运算, 所有出现2次的元素都会被置为0, 只留下出现一次的元素. 但这个题目中有2个元素出现一次(假设为n, m), 将所有元素^后, 得到的结果是 X = n^m
- 此时,如果我们能够将原数组根据X分为2部分, A = (x1, x1, y1, y1, n) 和 B = (z1, z1, h1, h1, m), 那么, A ^ X 就得到 n, B ^ X 就得到 m
- 那么如何分组呢? 类比我们区分奇偶数用 1 & num == 0 来区分, 所以我们可以用 X & num == 0来将原数组分为2组
示例代码:
def singleNumbers(self, nums: List[int]) -> List[int]:
x, y, n, m = 0, 0, 0, 1
for num in nums: # 步骤2. 将所有元素先进行^, 得到 n^m
n ^= num
while n & m == 0: # 步骤4. 通过 << 计算出合适的 m
m <<= 1
for num in nums: # 步骤3. 使用步骤4得到的m, 将数组分组并^得到 x,y
if num & m:
x ^= num
else:
y ^= num
return x, y