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

  • 相关阅读:
    Leetcode Spiral Matrix
    Leetcode Sqrt(x)
    Leetcode Pow(x,n)
    Leetcode Rotate Image
    Leetcode Multiply Strings
    Leetcode Length of Last Word
    Topcoder SRM 626 DIV2 SumOfPower
    Topcoder SRM 626 DIV2 FixedDiceGameDiv2
    Leetcode Largest Rectangle in Histogram
    Leetcode Set Matrix Zeroes
  • 原文地址:https://www.cnblogs.com/king-lps/p/10682503.html
Copyright © 2011-2022 走看看