原题:
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
分析:
查找问题,两个思路:
- 空间足够:hashmap => O(n)构建 + O(1)查找
- 空间不足:一开始想到用sort + binary search (时间为O(nlogn))。但是仔细想想,在内存不足的情况下,正常的quick/merge sort同样无法进行,需要external sort。那样的话,效率不如构建external hashmap
解题:
第一版
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
#建个字典,key=数组里的值,value=数组里的序
indices = {}
for idx, val in enumerate(nums):
indices[val] = idx
#迭代数组里每一个数,查找对应求和的差值是否在字典里存在
for idx, val in enumerate(nums):
x = target - val
if x in indices.keys():
idx2 = indices[x]
#自己不能和自己相加
if idx != idx2:
return [idx, idx2]
raise Exception("no found")
Runtime: 1969 ms
第二版:优化代码,去掉构建字典的O(n)迭代,字典构建和查找一同进行。
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
indices = {}
for idx, val in enumerate(nums):
x = target - val
if x in indices.keys():
idx2 = indices[x]
if idx != idx2:
return [idx, idx2]
indices[val] = idx
raise Exception("no found")
Runtime: 652 ms
速度缩短为原来的1/3
第三版:再优化。根据python的代码风格——EAFP重新改写,减少了对字典的查询访问。
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
indices = {}
for idx, val in enumerate(nums):
x = target - val
try:
idx2 = indices[x]
except KeyError:
pass
else:
if idx != idx2:
return [idx, idx2]
indices[val] = idx
raise Exception("no found")
Runtime: 42 ms
这一步优化令人吃惊地加快了15倍的速度!猜测是dict.keys()在每次循环中被调用,不断构建新的包含所有key的list。
于是又测试了x in indices
的运行速度:
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
indices = {}
for idx, val in enumerate(nums):
x = target - val
if x in indices:
idx2 = indices[x]
if idx != idx2:
return sorted([idx, idx2])
indices[val] = idx
return []
Runtime: 55 ms 果然!
第四版:再精简代码。idx != idx2
永远为True,因为字典的插入操作在查询之后。
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
indices = {}
for idx, val in enumerate(nums):
try:
return [idx, indices[target - val]]
except KeyError:
pass
indices[val] = idx
raise Exception("no found")
Runtime: 38 ms
空间:O(n)
时间:O(n)