【Leetcode】2sum

2sum是Leetcode上很经典的题,它可以延伸到3sum,4sum以及Ksum,在面试的时候很多面试官喜欢考这样的类型问题。在后面的博客中我会讲解它的延伸情况,这里先来看看2sum。

先贴一下Leetcode上面(Leetcode 1)关于2sum的描述:

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

常规的Brute Force解(两层循环,复杂度较高)容易超时
这个题可以从两个角度来思考:
(1) 若不对原始数组进行排序,用一遍循环通过Hash来找出满足条件的解
(2) 若对原数组进行排序,用首尾指针依次向中间靠拢,来找出满足条件的解

下面对上面两个思路分别进行解析:
对于第一个思路,由于要使得 a i + a j = a_i+a_j= ai+aj= target,也就是说只需在遍历 i i i 时,判断 target − a i -a_i ai在数组中即可。

对于数组 nums = [2, 7, 11, 5],通过一遍循环从第0号元素2开始,先将2存入一个空的Hash表中(Hash的key为nums中的元素,Hash的value为对应索引序号),那么{2:0}就被存起来了,再遍历到第1号元素7,计算target减去当前元素所得值是否在Hash表的键中,如果在则返回Hash表的那个键对应的序号和当前这个序号即可。

Python代码如下:

    def twoSum(nums, target):
        dicts = {}
        for i in range(len(nums)):
            if target-nums[i] in dicts:
                return [dicts[target-nums[i]], i]
            dicts[nums[i]] = i

对于第二个思路,先对 nums 进行排序,由于需要保存排序前的索引,所以 nums = [2, 7, 11, 5] 排序后写成 lists = [[2,0], [5,3], [7,1], [11,2]] 的形式,其中 lists[i][0] 表示 nums 中的元素,而 lists[i][1] 表示 nums 中元素对应的原始索引。因为排序会导致索引变化,所以需要将原始索引在排序时一起存起来。

先介绍一个数学思维:“有序数组的首尾渐进相夹”(即缩小包围圈),这不仅在这道题中求和会用到,而且它也是数据结构中的二分查找的核心。对于这道题的求和,称首指针为left,尾指针为right,如果 [left]+[right] >target([left]表示 left 对应的元素值),则需要使得 [left]+[right] 减小,即 right 要左移(因为数组元素是递增的,左边的元素要小于等于右边的元素),相应地, 如果 [left]+[right] <target,则需要使得 [left]+[right] 增大,即 left 要右移。

对 nums = [2, 7, 11, 5] 排完序后得到 [2, 5, 7, 11] (相应排序前序号为 [0, 3, 1, 2]),让左右指针从两头开始寻找,初始情况下 left = 0,right=3(注:这里的3是最大索引)。计算它们对应的元素之和,即 2+11 = 13 要大于 target,说明元素的和需要减小,故 left 不变,right要变成 right-1,这样就变成计算 2+7,而 2+7 刚好等于 target, 所以结束循环。循环是结束了,但是并不能返回 [left, right],因为排过序,所以应该返回排序前的索引序号,即返回 [lists[left][1], lists[right][1]]。

Python 代码如下:

    def twoSum(nums, target):
        lists = []
        for i in range(len(nums)):
            lists.append([nums[i], i])
        lists = sorted(lists, key = lambda s:s[0])
        l = 0; r = len(nums)-1
        while(l<r):
            if lists[l][0]+lists[r][0]==target:
                return [lists[l][1], lists[r][1]]
            elif lists[l][0]+lists[r][0]<target:
                l+=1
            else:
                r-=1

做题目注重的是思维,一个题目可以有多种解,需要通过做题目的过程去体会方法,这样才能真正学到东西。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值