[Leetcode] Two Sum

原题:

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].

分析:

查找问题,两个思路:

  1. 空间足够:hashmap => O(n)构建 + O(1)查找
  2. 空间不足:一开始想到用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)

    原文作者:Azurelore
    原文地址: https://www.jianshu.com/p/1159ec3b8642
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞