三数之和 - 灵神视频总结。

跟着 - b站up主刷题

这里面有个知识点: 相向双指针 。

167. 两数之和 II - 输入有序数组

1️⃣ 暴力解法

两遍循环,遍历第一个元素,接着从第二个元素开始找,判断两数之和是否和target相等,如果相等,直接返回。

时间复杂度 O(n^2)。 这样没有用到里面的一个性质,整个数组是有序的。

2️⃣ 相向指针解法

从题意中,可以知道,整个数组是非递减顺序排列 的,我们用最两头的元素相加和target比较,

  1. 如果nums[0] + nums[n-1] (两数相加) 比 target 大,那么 nums[1] ... nums[n-2] 中的任何一个数和 nums[n-1] 相加 都比target大,就需要把nums[n-1] 丢弃掉,用 nums[n-2] 元素和 nums[0]相加与target比较。
  2. 同理可得,如果nums[0] + nums[n-1] 比 target 小,那么 nums[1] ... nums[n-2] 中的任何一个数和 nums[n-1] 相加 都比target小,就需要把nums[0] 丢弃掉,用 nums[1] 元素和 nums[i-1]相加与target比较。

代码: 时间复杂度 O(n)

class Solution(object):
    def twoSum(self, numbers, target):
        """
        :type numbers: List[int]
        :type target: int
        :rtype: List[int]
        """
        left = 0 
        right = len(numbers) - 1
        while left < right:
            s = numbers[left] + numbers[right]
            if s == target:
                break 
            if s < target:
                left +=1
            else:
                right -=1

        return [left+1, right+1]

15. 三数之和

这题可以说是两数之和的升级版。

1️⃣ 暴力解法

这题当然也可以用暴力法解决,那么时间复杂度就是O(n^3) ,三遍循环即可。

2️⃣ 相向双指针解法。

通过上一题可以知道,如果数组有序的话,我们就可以使用双向双指针,可以把O(n^2) 时间复杂度降低到O(n), 那么只要我们从第一个元素开始遍历,那么另外两个元素 可以转化为相加为0的问题。

题意中有几个要求:

  1. 三元组的顺序不重要。
  2. i < j < k
  3. 答案中不包含重复元素。

只需要我们把数组排序,从第一个元素开始遍历,剩下的两个元素,就可以使用双向双指针即可。

答案中不包含重复元素:

[-4,-1,-1,0,1,2] 比如 nums[1] + num[3] + nums[4] = 0 , nums[2] + num[3] + nums[4] = 0

那么如何过滤掉这种情况呢, 就是下一次进入的时候,发现当前的num[i] 和上一个nums[i-1] 相等,就过滤掉。注意要过滤掉i=0 的情况,也就是说,nums[-1] 的情况。 为什么要用continue,是因为 for循环,自动+1。

if i > 0 and nums[i-1] == x:
                continue 

对于j 和 k 的情况,同样的道理。 当找到了一组满足条件的解时,j 到 k 要遍历一遍,此时j已经+1了, 就如果nums[j] == nums[j-1] ,继续j+=1, 跳过这个k。

同样的对于k来说, k已经-1, k 到j 开始遍历,如果 num[k] = nums[k+1] , 继续让k-=1 , 跳过这个k。

这题还有两个小优化:

  1. 如果 x + nums[i+1] +num[i+2] > 0 , 那么直接 break吧, 从大到小排序的,后面的已经不可能再有=0的解了。
  2. 如果 x + nums[-1] + nums[-2] < 0, 直接continue 吧, 就需要从下一个x,这个x 已经不可能找到=0的解了。
class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        nums.sort() #  [-1,0,1,2,-1,-4] => [-4,-1,-1,0,1,2]
        ans = []
        print(nums)

        n = len(nums)
        for i in range(n-2):
            x = nums[i]
            if x + nums[i+1] + nums[i+2]  >0:
                break 
            if x + nums[-1] + nums[-2] <0:
                continue
            if i > 0 and nums[i-1] == x:
                continue 
            j = i + 1 
            k = n - 1
            while j < k : 
                s = x + nums[j] + nums[k]
                if s < 0:
                    j +=1 
                elif s > 0:
                    k -=1
                else:
                    ans.append([x, nums[j], nums[k]])
                    j += 1
                    while j < k and nums[j] == nums[j-1]:
                        j +=1
                    k -= 1
                    while k > j and nums[k] == nums[k+1]:
                        k -=1
        return ans 



s = Solution()
a = [-1,0,0,1,2,-1,-4]

print(s.threeSum(a))
  • 24
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值