LeetCode 第1题:两数之和(Python3多种解法+时间复杂度分析)

1:问题描述

来源:LeetCode

难度:简单


问题详情:

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

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

提示:

  • 2 <= nums.length <= 104
  • 109 <= nums[i] <= 109
  • 109 <= target <= 109

只会存在一个有效答案

进阶:你可以想出一个时间复杂度小于 O( n 2 n^{2} n2)的算法吗?


示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

2:暴力for循环

一个最简单的也是最直接想到的解法,是利用双层for循环遍历查询当前索引和其之后的数相加是否满足target

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """

        for i in range(0, len(nums)-1):
            for j in range(i+1, len(nums)):
                sum_result = nums[i] + nums[j]
                if sum_result == target:
                    return [i, j]

接下来逐句分析一下这种解法的时间复杂度。

  1. for i in range(0, len(nums)-1) 第一个for循环是从0 -> n-2共循环n-1次;其中n指的是列表nums的长度;
  2. for j in range(i+1, len(nums)) 第二个for循环是从i+1 -> n-1共循环n-i-1次;
  3. sum_result = nums[i] + nums[j] 分析其执行了多少次,当i=0时,j:1 -> n-1n-1次;当i=1时,j:2 -> n-1n-2次;…;当i=n-2时,j:n-1 -> n-11次;所以其总共执行的次数是一个等差数列,因此由等差数列的求和公式可得,该语句总共执行了Sn=(n-1)*(n-2 + 1)/2=0.5n²-n+0.5次;
  4. if sum_result == target该判断语句的判断次数与sum_result = nums[i] + nums[j]的执行次数是相同的,所以同样是0.5n²-n+0.5次;
  5. return [i, j]该语句在整个程序中只执行1次;

综上所述,整段代码的最高次项是,因此该程序的时间复杂度是 O( n 2 n^{2} n2);

所以虽然该代码思想较为简单、容易想到,但是其时间复杂度无法满足进阶要求。

2:解法1——首尾递进查找

该解法首先利用Python自带的sorted函数排序(默认升序),然后利用首尾指针法,对首尾相加的值判断,如果和大于target,那就需要将两个数中的最大者变小些,所以将尾部指针左移;相反,如果和小于target,那就需要将两个数中的最小者变大些,所以将首部指针右移;如果相等,则返回索引。

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """

        length = len(nums)
        sorted_id = sorted(range(length), key=lambda k: nums[k])
        

        head = 0
        tail = length - 1

        head_idx = sorted_id[head]
        tail_idx = sorted_id[tail]

        add = nums[head_idx] + nums[tail_idx]

        while True:
            if add == target:
                return [head_idx, tail_idx]
            elif add > target:
                tail -= 1
            elif add < target:
                head += 1
            
            head_idx = sorted_id[head]
            tail_idx = sorted_id[tail]

            add = nums[head_idx] + nums[tail_idx]

接下来分析该解法的时间复杂度。

  1. 排序代码sorted_id = sorted(range(length), key=lambda k: nums[k])使用的是python自带的sorted函数排序,其是 timsort排序 算法,时间复杂度为O(nlogn),关于timsort排序可以参考:timsort
  2. 下面的while循环中最多循环n次,而下面的if else语句也最多执行n次,因此这部分语句的时间复杂度为O(n)
  3. 时间复杂度大小的比较:
    O(1) < O(logn) < O(n) < O(nlogn) <O( n 2 n^{2} n2)< O( n 3 n^{3} n3)< O( 2 n 2^{n} 2n)
  4. 因此本程序的时间复杂度为O(nlogn)

3:解法2——Hash查询

第二种解法已经大幅度降低时间复杂度了,但是还有一种更快的解法:利用Hash查询的方式求解。依次遍历nums中的数据num,然后查询target-num是否在字典的key中,如果在就直接返回它们两个的索引;否则就添加 {数据num:其索引i}键值对。

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        hashDict = {}
        for i, num in enumerate(nums):
            if target - num in hashDict:
                return [hashDict[target - num], i]
            hashDict[nums[i]] = i
        return []

接下来分析其时间复杂度。

  1. 查询一次字典的key的时间复杂度是O(1),最多执行n次,因此时间复杂度O(n).
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

little student

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值