两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

方法一:暴力法

class Solution:
    def twoSum(self, nums, target):
        for i in range(len(nums)):
            for j in range(i+1,len(nums)):
                other = target - nums[i]
                if other == nums[j]:
                    return [i,j]
        return None

遍历每一个元素x,并查找是否存在一个值与target - x相等的目标元素。(j从i+1开始,是因为如果前面的i个元素的(target - i)都不存在于该列表中,那么i之后的元素的(target - i)不存在于i之前的元素中。

算法分析:

  • 时间复杂度:O(n2)。对于每个元素,我们通过遍历整个列表其它元素寻找它所对应的目标元素,耗费O(n)的时间。
  • 空间复杂度:O(1)。

哈希表

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
方法二:两遍哈希表
通过以空间换取速度的方式,我们可以将查找时间从O(n)降低到O(1)。哈希表正是为此目的而构建的。
class Solution:
    def twoSum(self, nums, target):
        hashmap = {}
        for i,j in enumerate(nums):
            hashmap[j]=i
        for i,j in enumerate(nums):
            k = hashmap.get(target-j)
            if  k is not None and k != i:
                return [i,k]

两次迭代,第一次迭代中我们将每个元素的值和它的索引添加到哈希表中。在第二次迭代中我们将检查每个元素对应的目标元素k=hashmap.get(target-j)是否在表中。该元素不能于i相等。假设表中有两个相等的元素,第二次索引的值会改为后一个重复元素的索引,如果第一个重复值找到了函数就结束,没找的话,第二次重复元素也肯定找不到,所以在查找中不会产生错误。

  • 时间复杂度分析:O(n)。我们遍历列表两次。哈希表将查找的时间缩短为O(1),所以时间复杂度为O(1)。
  • 空间复杂度:O(n)。所需的额外空间取决于哈希表中存储的元素数量,该表中存储了n个元素。

方法三:一遍哈希表

class Solution:
    def twoSum(self, nums, target):
        hashmap = {}
        for i,j in enumerate(nums):
            k = target -j
            if k in hashmap:
                return [hashmap.get(target-j), i]
            hashmap[j] = i

将遍历过的元素,以及它的索引加入表中,后续的元素在表中查找target - i。

复杂度分析:

  • 时间复杂度:O(n)。只遍历了一次包含n个元素的列表,在表中进行的每次查找只花费O(1)的时间。
  • 空间复杂度:O(n)。所需的空间取决于哈希表中的元素数量,最多存储n个元素(即遍历完没找到)。
posted @ 2021-06-21 10:53  Mr-Yao  阅读(57)  评论(0编辑  收藏  举报