ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

**15. 3Sum

2019-04-10 11:55:13  阅读:240  来源: 互联网

标签:head 15 target nums 3Sum 三元组 tail 两数


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

标签:head,15,target,nums,3Sum,三元组,tail,两数
来源: https://www.cnblogs.com/king-lps/p/10682503.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有