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

分析##

Leetcode的第一道题目,想想看,很简单嘛,用两层循环,暴力穷举,一下子就可以实现,于是立马动手写代码,如下:

Solution 1:###

class Solution:
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        for i in range(len(nums)):
            for j in range(i + 1, len(nums)):
                if target == nums[i] + nums[j]:
                    return [i, j]
        return None

sol = Solution()
test_nums = [1, 3, 5, 7]
test_target = 6
print(sol.twoSum(test_nums, test_target))

算法分析

  • 时间复杂度:\(O(n^2)\)。对于每一个元素,我们尝试在余下的元素集合中遍历以确定其差值后的结果,需要\(O(n)\),总对于n个元素,时间复杂度为\(O(n^2)\)
  • 空间复杂度:未开辟新的空间,故为\(O(1)\)

代码在LeetCode网站上测试通过,正当我满心欢喜的提交时,出现Time Limit Exceeded。于是,我尝试多次提交,依然出现这个问题,以为是网站bug或超时,于是开始Google查找问题。果然被打脸了,虽然LeetCode标注此题为简单,但也不是简单到这种程度。

Solution 2###

很显然,暴力穷举的方法能完成任务,但很耗时。直观来看,该方法的时间复杂度为\(O(n^2)\),所以出现Time Limit Exceeded。该方法虽然时间复杂度较高,但空间复杂度仅为\(O(1)\)。于是尝试改进方法,如何将两次遍历变成一次遍历呢?首先想到的就是hash table,如果我们将索引和值放在hash table中,那么查找元素就只需要\(O(1)\)的常量时间复杂度。我们只需要遍历一次列表,每遍历一次,就用target减去当前的值,得到的结果在hash table中查找,若存在,说明找到。若不存在,则未找到。
接下来马上用Python默认的hash table实现的数据结构dict来实现此算法。

class Solution:
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        dic = {}
        for key, value in enumerate(nums):
            dic[value] = key
        
        for i in range(len(nums)):
            component = target - nums[i]
            if component in dic:
                return [i, dic[component]]
        return None

sol = Solution()
test_nums = [1, 3, 5, 7]
test_target = 6
result = sol.twoSum(test_nums, test_target)
print(result)

算法分析

  • 时间复杂度:\(O(n)\)。我们遍历列表两次\(O(2n),hash 查找为\)O(1)。则总的时间复杂度为\(O(n)\)
  • 空间复杂度:开辟了新的数据结构hash table,取决于列表的长度。故为\(O(n)\)

Solution 3###

第三种方式可以改进hash table的使用方式,我们可以将两次遍历变成1次遍历。算法如下:先创建空的字典,然后循环列表,若component的值在字典中,则直接返回,若不在,则将索引为i的值存放在字典中。

class Solution:
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        dic = {}
        for i in range(len(nums)):
            component = target - nums[i]
            if component in dic:
                return [dic[component], i]
            dic[nums[i]] = i
        return None

sol = Solution()
test_nums = [1, 3, 5, 7]
test_target = 6
print(sol.twoSum(test_nums, test_target))

算法分析

  • 时间复杂度:\(O(n)\)。遍历一次列表为\(O(n)\),hash查找为\(O(1)\)。则总的时间复杂度为\(O(n)\)
  • 空间复杂度:与方案二相同,仍为\(O(n)\)
posted @ 2018-11-05 22:05  Jeffrey_Yang  阅读(121)  评论(0编辑  收藏  举报