题目描述:
给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。
进阶:你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?
示例 1:
输入:nums = [1,2,1,3,2,5]
输出:[3,5]
解释:[5, 3] 也是有效的答案。
示例 2:
输入:nums = [-1,0]
输出:[-1,0]
示例 3:
输入:nums = [0,1]
输出:[1,0]
提示:
2 <= nums.length <= 3 * 104
-231 <= nums[i] <= 231 - 1
除两个只出现一次的整数外,nums 中的其他数字都出现两次
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/single-number-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解:
分析题目可以得出的有用信息:
只要将不重复的两个数分在不同的两个组中,
根据类似题*136. 只出现一次的数字*,
对每个组所有数进行一次异或操作就可以得出两个数
算法如下:
首先进行一次排序
结合折半查找
当right-left > 1
将数据折半,注意避免在两个相同的数中间切开
先取数组的左半边,计算所有数字的异或结果first
若first结果为 0,则两个数均在右半边,重新查找右半边
若first结果不为0,取nums的右半边,计算所有数字的异或结果second
若结果second为0,则两个数均在左半边,重新查找左半边
若second结果不为0,则两个数分列左右两半,分别为first,second
当right-left == 1时,left和right的位置就是这两个数
时间复杂度:O(nlogn) 排序 + 查找0 + 折半计算= nlogn + n + nlogn
注意:
首先要对数组进行一次排序(当然,排序后依次遍历也可以发现单独出现的数,不过我就要用折半。。。之前写出来了折半不舍得放弃。。。)
分两边的时候要避免在两边分别产生新的不重复的数,nums[mid] == nums[mid + 1]则表明将两个相同的数分开了,采用 mid += 1 解决
数组中有一个数是0的时候要特殊处理一下,如nums = [0,1,1, 2],分半左边为0会被忽略
class Solution:
"""
执行用时:60 ms, 在所有 Python3 提交中击败了15.84% 的用户
内存消耗:15.8 MB, 在所有 Python3 提交中击败了68.32% 的用户
"""
# 返回nums一段上所有数字的 异或 结果
def fun_xor(self, nums: List[int], left: int, right: int) -> int:
return reduce(lambda x, y: x ^ y, nums[left:right+1])
def fun_zheban(self, nums: List[int], left:int, right:int) -> List[int]:
if right - left > 1:
mid = (right + left)//2
# 恰好折半处产生不重复的数分列两边,即折半处两个数相等,如[1, 2, 2, 3, 3, 4, 4, 5]
if nums[mid] == nums[mid + 1]:
mid += 1
first = self.fun_xor(nums, left, mid)
if first == 0:
# 注意 mid+1 避免两次传入 nums[mid]
# 注意递归调用时,调用自身需要加 return
return self.fun_zheban(nums, mid + 1, right)
else:
# 注意 mid+1 避免两次传入 nums[mid]
second = self.fun_xor(nums, mid + 1, right)
if second == 0:
return self.fun_zheban(nums, left, mid)
else:
return [first, second]
else: # right-left == 1
return [nums[left], nums[right]]
def singleNumber(self, nums: List[int]) -> List[int]:
nums.sort()
# if 0 in nums: # 注意,特殊情况是数组中只有一个0,有两个0无所谓
if nums.count(0) == 1:
return [0, self.fun_xor(nums, 0, len(nums) - 1)]
else:
return self.fun_zheban(nums, 0, len(nums) - 1)
本解非最优,最优题解可以参照官方题解