【位运算】力扣136: 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例:
输入: [4,1,2,1,2]
输出: 4
方法1:暴力解法
设置两个指针,前指针一格一格后移遍历。
在前指针固定的情况下,后指针遍历前指针后的所有数字。
class Solution:
def singleNumber(self, nums: List[int]) -> int:
n = len(nums)
for i in range(n):
flag = 0
for j in range(n):
if nums[i] == nums[j] and i != j:
flag += 1
break
if flag == 0:
res = nums[i]
break
return res
超出时间限制
时间复杂度:二重循环,为O(N^2)
空间复杂度:除了两个指针外没有额外空间消耗,O(1)
方法2:哈希表
利用hashtable记录已经出现过的数字,避免重复遍历
class Solution:
def singleNumber(self, nums: List[int]) -> int:
ht = [0] * 100000 # 注意长度要大于10000
n = len(nums)
for i in range(n):
ht[nums[i]] += 1
for i in range(n):
if ht[nums[i]] == 1:
return nums[i]
时间复杂度:两次遍历,O(N)
空间复杂度:一个哈希表,O(N)
方法3:快排
如何再继续降低复杂度呢?这样就想到了排序:先用快排将数组排序,找到与前后都不一样的数字即可。
一种暴力解法
class Solution:
def singleNumber(self, nums: List[int]) -> int:
nums.sort()
n = len(nums)
for i in range(1, n - 1):
if nums[i] != nums[i - 1] and nums[i] != nums[i + 1]:
return nums[i]
if n > 1:
if nums[0] != nums[1]:
return nums[0]
if nums[n - 1] != nums[n - 2]:
return nums[n - 1]
else:
return nums[0]
时间复杂度:一次快排一次遍历,O(NlogN)
空间复杂度:O(N)
方法4:异或
题目说:除了某个元素只出现一次以外,其余每个元素均出现两次。这是个突破口 —— 异或运算!
- 异或运算具有交换律和结合律
- 一个数【异或】它本身为 0,一个数【异或】0 还是它本身,即 x ^ x = 0 和 x ^ 0 = x
∴ 把所有数字都异或起来就是所要的答案。出现两次的所有数字按位异或的结果是 0,0 与出现一次的数字异或可以得到这个数字本身。
class Solution:
def singleNumber(self, nums: List[int]) -> int:
for i in range(1, len(nums)):
nums[0] ^= nums[i]
return nums[0]
一行代码
class Solution:
def singleNumber(self, nums: List[int]) -> int:
return reduce(lambda x,y:x^y, nums)
作者:Jam007
链接:https://leetcode.cn/problems/single-number/solution/by-jam007-i6j8/
时间复杂度:一遍遍历,O(N)
空间复杂度:无任何额外空间,O(1)
方法5 取巧
只有一个数出现一次,每个不同的数总和 * 2 作差
class Solution:
def singleNumber(self, nums: List[int]) -> int:
return 2*sum(set(nums))-sum(nums) # set(nums)去掉数组中的重复数字
作者:Jam007
链接:https://leetcode.cn/problems/single-number/solution/by-jam007-i6j8/

浙公网安备 33010602011771号