问题描述:
版本一:
首先最常见也是最不可取的通过暴力for循环求解,得到的结果自然时间复杂度和空间度都高
class Solution(object):
def twoSum(self, nums, target):
for i in range(len(nums)):
for j in range(len(nums)):
if(i==j):
print('a')
elif(nums[i]+nums[j])==target:
break
else:
continue
break
return i,j
Solution()
版本二
版本二通过构建字典dict,将存在字典的键值对通过查表来找,时间复杂度为
O
(
n
)
\Omicron (n)
O(n)但这种情况下我们要考虑到一种很特殊的情况,因为字典通过键来找值是很方便的,反之不同,所以我们将索引设为值,数字设置为键是比较好的方法,但是因为字典是键唯一而值可以不唯一的,如果我们将数字设置为键就可能造成一种冲突,例如:
输入的
l
i
s
t
=
[
3
,
3
]
,
t
a
r
g
e
t
=
6
list=[3,3],target=6
list=[3,3],target=6,如果按照以上的方法生成字典的话,就会造成字典只有一对键值对:
{
3
:
0
}
\left\{3:0\right\}
{3:0}
而不是:
{
3
:
0
,
3
:
1
}
\left \{3:0 ,3:1 \right \}
{3:0,3:1}
因此我们以相反的方式构建字典,但是这样从值去取得键不方便,而且会造成字典的重复利用,和题目中每个元素利用一次不符合,因此我们转到版本三,也是官方给出的版本.
class Solution(object):
def twoSum(self, nums, target):
dict_={}
for i,num in enumerate(nums):
dict_[i]=num
for index,nums_ in enumerate(nums):
s=dict_.copy()
del s[index]
other_nums=target-nums_
if other_nums in s.values():
return [index,list(s.keys())[list(s.values()).index(other_nums)]]
版本三
版本三在版本二的基础上,哈希求法,解决了键重复和重复利用同一个元素的问题,不仅效率更好而且更节约时间,如何做到的呢?关键在于这个代码:
if another_num in hashmap:
return [hashmap[another_num], index]
hashmap[num] = index
我们版本二构建是将整个字典构建出来,再去寻找,而此版本一边赋值一边寻找,刚开始我认为这并不可能,但仔细思考才发现这种思路的精妙之处.首先举例我们找的两个值是A和B:
A
+
B
=
t
a
r
g
e
t
A+B= target
A+B=target
两个数字是相互,例如我找到A,注意此时字典中没有B,然后我们迭代到B的时候,再通过字典找到A,这解决了什么问题了?我们版本二提出的键重复的问题,如果
A
=
3
,
B
=
3
A=3,B=3
A=3,B=3就会产生版本所说的键重复,但如果按照版本三边赋值边迭代,当找到B的时候,我们就不会面对这个问题,因为B的索引是迭代过程中通过enumerate,而A的索引是通过找字典的键值对。
同样版本三可以让过程在一个for循环下,边赋值边寻找,节省时间和内存。
class Solution:
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
hashmap = {}
for index, num in enumerate(nums):
another_num = target - num
if another_num in hashmap:
return [hashmap[another_num], index]
hashmap[num] = index
return None
总而言之
第一个是字典的应用是的时间复杂度降低
第二个是边赋值边索引解决了键值冲突的问题
第三个字典的值比键好找,所以最好将索引用作值