0. 原理
具体可以参考我的另一篇文章。
1. 两数之和(leetcode_1)
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 示例: 给定 nums = [2, 7, 11, 15], target = 9> 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1]
此题有三种解法:
- 暴力法
时间复杂度;空间复杂度
- 两遍哈希表法
时间复杂度;空间复杂度
- 一遍哈希表法
时间复杂度;空间复杂度
1.1 暴力解法
时间复杂度;空间复杂度
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
length = len(nums)
for first_index in range(length-1):
for second_index in range(first_index+1, length):
if nums[first_index] + nums[second_index] == target:
return [first_index, second_index]
else:
return -1
1.2 两遍哈希表
即空间换时间的思想。时间复杂度;空间复杂度。
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
dict_ = {}
for index, val in enumerate(nums):
dict_[val] = index
for index, val in enumerate(nums):
if target - val in dict_.keys():
if index != dict_[target-val]:
return [index, dict_[target-val]]
return -1
1.3 一遍哈希表法
即有点类似于动态规划搜索,一边遍历一边存储一边查找的思想。时间复杂度;空间复杂度。
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
dict_ = {}
for index, val in enumerate(nums):
if target - val in dict_.keys():
return [index, dict[target-val]]
else:
dict_[val] = index
return -1
这里需要注意两点:
- 哈希表的hashMap.containsKey()平均复杂度为,最坏状况为,实际中看做即可。
- 虽然一遍哈希和两遍哈希时间和空间复杂度表面上一样,但是实际运行中,一遍哈希还是比两遍哈希更快的,因为实际情况中需要完全遍历到列表末尾的概率很小,但是他们的整体复杂度是相同的,这一知识点具体可以参考我的另一篇关于复杂度的文章。
- 暴力法和哈希法各有各的优劣,并没有绝对的好与坏之分,应该具体情况具体分析。比如
- 当我们空间足够大需要时间尽可能短,即算法相应尽可能快的话,当然哈希法更好;
- 当列表中的数字非常多,我们的空间内存不足,并且并不太在意时耗时,当然暴力法更好。