这次的题目内容如图所示:
①第一种解法:使用字典
作为一个小白,我并不知道一些什么奇奇怪怪的神奇算法,所以最开始只能老老实实用遍历加上额外空间来把题目解出来先。
为了尽可能降低时间复杂度,我选择用字典来记录数字的出现次数,遍历一次把nums列表中所有数字作为key加入到dict中然后将其出现次数作为value,再遍历一次去字典里面找出value为1的key,并返回:
class Solution:
def singleNumber(self, nums: List[int]) -> int:
#使用额外的空间
lens = {}
for i in range(len(nums)):
if nums[i] in lens.keys():
lens[nums[i]] += 1
else:
lens[nums[i]] = 1
for i in range(len(nums)):
if lens[nums[i]] == 1:
return nums[i]
②第二种解法:使用异或操作符
用第一种方法做完后,我想了一会没有想出来可以怎么样在保持时间复杂度的情况下还能不用额外空间来操作,于是直奔评论区,发现大神们都是用异或操作符来写的。看完后我只能说一句牛逼,然后依葫芦画瓢写了一个:
class Solution:
def singleNumber(self, nums: List[int]) -> int:
#不使用额外的空间
#评论区学到的,用异或
a = 0
for i in nums:
a ^= i
return a
这里补充一下,异或操作符的逻辑是这样的:
异或的数学符号为“⊕”,计算机符号为“xor”。其运算法则为:a⊕b = (¬a ∧ b) ∨ (a ∧¬b)。简而言之,就是输入的值不同,结果是1,否则是0。在python中异或的操作符为^。
在实际应用中,有以下性质(摘自百度百科):
- a ⊕ a = 0
- a ⊕ b = b ⊕ a
- a ⊕b ⊕ c = a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c;
- d = a ⊕ b ⊕ c 可以推出 a = d ⊕ b ⊕ c.
- a ⊕ b ⊕ a = b;
- 若x是二进制数0101,y是二进制数1011,则x⊕y=1110
虽然这里是一步一步来实现异或的操作,但是实际效果可以等同于对所有元素进行异或,因为本身异或的操作也在不停地进行操作。在结合律(第3点)的作用下,相同的元素均为0,0与任何数字异或的结果都是这个数字本身,因此就能把那个唯一落单的数字找出来。
③第三种方法:提高时间复杂度,不用额外创建空间的遍历
这种方法纯粹是为了不用额外空间而想出来的,效率比较低,运行速度太慢了(其余方法都是在50ms左右,这个快7000ms了,不过还好能跑出来😂)。进行双重遍历,第一层遍历直到倒数第二个元素,第二层遍历从第一层遍历到的元素下一个元素开始遍历,如果两次遍历的元素相等,就跳出来,把这两个元素都给删掉,然后重新从头遍历,直到只有一个元素,然后返回剩下的那个元素。
class Solution:
def singleNumber(self, nums: List[int]) -> int:
#自己想的提高时间复杂度
while len(nums) != 1:
for i in range(len(nums)):
count = 0
for j in range(i+1, len(nums)):
if nums[i] == nums[j]:
nums.pop(j)
nums.pop(i)
count = 1
break
if count == 1:
break
return nums[0]
④第四种方法:用set去重
这个也是在评论区看到的,我觉得也是十分优秀,于是记录一下。用set对nums list去重并求和,然后将结果乘以2再减去nums求和的结果,这样得到的结果就是落单的那个元素。因为set去重后结果乘以2相当于所有元素都有两个了,但是nums落单的元素只有一个,所以相减自然会多出那个一个来。这样写代码相当简洁。
class Solution:
def singleNumber(self, nums: List[int]) -> int:
#评论区看到的,虽然想到了可以用加和的方法来操作,但是没有想到用set
return sum(set(nums)) * 2 - sum(nums)
这个评论下面的评论说用set的时间复杂度就不止O(n)了,于是我就去查了一下关于set的时间复杂度的内容。看了几篇文章之后发现,set是通过hash表来实现的,因此set的时间复杂度依旧是O(n)。
但是用了set似乎会创建一个hash表来存储数值,虽然过程中并没有显式地使用额外的空间,但我觉得应该也是有用空间来存储的,只不过是临时使用的,在算完之后就销毁了。
具体关于set的内容感兴趣的朋友可以参考以下几篇文章:
Python dict和set的底层原理
这篇文章里面有延申链接,也可以看看。
python set()去重的底层原理