zoukankan      html  css  js  c++  java
  • **15. 3Sum

    1. 原始题目

    给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

    注意:答案中不可以包含重复的三元组。

    例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
    
    满足要求的三元组集合为:
    [
      [-1, 0, 1],
      [-1, -1, 2]
    ]
    
    在真实的面试中遇到过
     

    2. 解法

    分析:此题的难点在于突破时间限制。暴力是3立方复杂度。

    一种解法是将数组先排序,然后分别以负数为target,将后面的数组由3数之和变为2数之和问题。

    此外如果排序后第一个数大于0,则后续所有数肯定也大于0,这种情况肯定不可能有三数之和=0。

    上图为核心思路:Target从最左边向非正数区间移动,对于每个Target取值,都有Head(从target下一位开始)和tail(从尾部开始),当head<tail时,两者相向移动。注意这里可以加入去重操作:例如当tail移到第二个1时,判断其左边也是1,说明这个1不必再看,所以tail应该直接移到0!head原理一样,head每次移动都判断当前head和右边的head取值是否一样,一样则head+=1。其实对于每个target循环取值,固定一个target取值的时候,这时对于后面的所有序列就变成了一个2数之和问题:

    target=-4, 则求解-2~6的两数之和为4问题。

    target=-2,则求解-1~6的两数之和为2的问题。

    target=-1,则求解0~6的两数之和为1的问题。

    .......

    target =1>0。结束,返回结果并退出。

    3. 实现

     1 class Solution:
     2     def threeSum(self, nums):
     3         if len(nums)<3: return []
     4         results = []
     5         
     6         L = sorted(nums)  # 排个序,由小到大
     7         i = 0
     8         
     9         for i in range(len(L)):
    10             if L[i]>0: break        # 如果首部都走到正数区间了,直接退出
    11             if (i>0) and (L[i]==L[i-1]):continue    # 如果当前数和前面的数一样,为了去重复,继续下一个
    12             target = 0-L[i]          # target为第i个元素的负数
    13             head = i+1               # head从target下一个位置起向右走
    14             tail = len(L)-1          # tail从末尾向左走 
    15             while(head<tail):        # 当首尾没相遇的时候
    16                 if L[head]+L[tail]==target:     # 找到一个三数之和为0的情况
    17                     results.append([L[head],L[tail],L[i]])     # 加入结果
    18                     
    19                     while (head<tail)and(L[head]==L[head+1]):head+=1   # 去重,当前head右移
    20                     while (head<tail)and(L[tail]==L[tail-1]):tail-=1   # 去重,当前tail左移
    21                     head+=1     # 移到下一位不重复的数
    22                     tail-=1     # 移到下一位不重复的数
    23                 elif L[head]+L[tail]>target:    # 若两数之和太大,那么tail应该左移一下
    24                     tail-=1 
    25                 else:                           # 若两数之和太小,那么head应该右移一下
    26                     head+=1
    27             i+=1
    28  
    29         return results

    验证:

    1 s = Solution()
    2 print(s.threeSum([-4,-2,-2,-2,0,1,2,2,2,3,3,4,4,6,6]))

    [[-2, 6, -4], [0, 4, -4], [1, 3, -4], [2, 2, -4], [-2, 4, -2], [0, 2, -2]]

  • 相关阅读:
    HTML & CSS & JavaScript 从一个表格到一个灰阶颜色表(目录)
    HTML & CSS & JavaScript 从一个表格到一个灰阶颜色表 01
    HTML & CSS & JavaScript 从一个表格到一个灰阶颜色表 03
    HTML & CSS & JavaScript 从一个表格到一个灰阶颜色表 02
    一点点读书笔记
    SSO-CAS实现单点登录服务端
    SpringBoot打包部署简单说明
    Java 8 新特性-Stream更优雅的处理集合入门
    Java提取文本文档中的所有网址(小案例介绍正则基础知识)
    dubbo入门和springboot集成dubbo小例子
  • 原文地址:https://www.cnblogs.com/king-lps/p/10682503.html
Copyright © 2011-2022 走看看