Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

  • Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
  • The solution set must not contain duplicate triplets.
    For example, given array S = {-1 0 1 2 -1 -4},

    A solution set is:
(-1, 0, 1)
(-1, -1, 2)

这道题让我们求三数之和,比之前那道 Two Sum 要复杂一些,博主考虑过先 fix 一个数,然后另外两个数使用 Two Sum 那种 HashMap 的解法,但是会有重复结果出现,就算使用 TreeSet 来去除重复也不行,会 TLE,看来此题并不是考 Two Sum 的解法。来分析一下这道题的特点,要找出三个数且和为0,那么除了三个数全是0的情况之外,肯定会有负数和正数,还是要先 fix 一个数,然后去找另外两个数,只要找到两个数且和为第一个 fix 数的相反数就行了,既然另外两个数不能使用 Two Sum 的那种解法来找,如何能更有效的定位呢?我们肯定不希望遍历所有两个数的组合吧,所以如果数组是有序的,那么就可以用双指针以线性时间复杂度来遍历所有满足题意的两个数组合。

对原数组进行排序,然后开始遍历排序后的数组,这里注意不是遍历到最后一个停止,而是到倒数第三个就可以了。这里可以先做个剪枝优化,就是当遍历到正数的时候就 break,为啥呢,因为数组现在是有序的了,如果第一个要 fix 的数就是正数了,则后面的数字就都是正数,就永远不会出现和为0的情况了。然后还要加上重复就跳过的处理,处理方法是从第二个数开始,如果和前面的数字相等,就跳过,因为不想把相同的数字fix两次。对于遍历到的数,用0减去这个 fix 的数得到一个 target,然后只需要再之后找到两个数之和等于 target 即可。用两个指针分别指向 fix 数字之后开始的数组首尾两个数,如果两个数和正好为 target,则将这两个数和 fix 的数一起存入结果中。然后就是跳过重复数字的步骤了,两个指针都需要检测重复数字。如果两数之和小于 target,则将左边那个指针i右移一位,使得指向的数字增大一些。同理,如果两数之和大于 target,则将右边那个指针j左移一位,使得指向的数字减小一些,代码如下:

解法一:

class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
if (nums.empty() || nums.back() < || nums.front() > ) return {};
for (int k = ; k < (int)nums.size() - ; ++k) {
if (nums[k] > ) break;
if (k > && nums[k] == nums[k - ]) continue;
int target = - nums[k], i = k + , j = (int)nums.size() - ;
while (i < j) {
if (nums[i] + nums[j] == target) {
res.push_back({nums[k], nums[i], nums[j]});
while (i < j && nums[i] == nums[i + ]) ++i;
while (i < j && nums[j] == nums[j - ]) --j;
++i; --j;
} else if (nums[i] + nums[j] < target) ++i;
else --j;
}
}
return res;
}
};

或者我们也可以利用 TreeSet 的不能包含重复项的特点来防止重复项的产生,那么就不需要检测数字是否被 fix 过两次,不过个人觉得还是前面那种解法更好一些,参见代码如下:

解法二:

class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
set<vector<int>> res;
sort(nums.begin(), nums.end());
if (nums.empty() || nums.back() < || nums.front() > ) return {};
for (int k = ; k < (int)nums.size() - ; ++k) {
if (nums[k] > ) break;
int target = - nums[k], i = k + , j = (int)nums.size() - ;
while (i < j) {
if (nums[i] + nums[j] == target) {
res.insert({nums[k], nums[i], nums[j]});
while (i < j && nums[i] == nums[i + ]) ++i;
while (i < j && nums[j] == nums[j - ]) --j;
++i; --j;
} else if (nums[i] + nums[j] < target) ++i;
else --j;
}
}
return vector<vector<int>>(res.begin(), res.end());
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/15

类似题目:

Two Sum

3Sum Smaller

3Sum Closest

4Sum

参考资料:

https://leetcode.com/problems/3sum/

https://leetcode.com/problems/3sum/discuss/7380/Concise-O(N2)-Java-solution

https://leetcode.com/problems/3sum/discuss/7373/Share-my-simple-java-solution

http://www.lifeincode.net/programming/leetcode-two-sum-3-sum-3-sum-closest-and-4-sum-java/

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] 15. 3Sum 三数之和的更多相关文章

  1. [leetcode]15. 3Sum三数之和

    Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find ...

  2. 【LeetCode】15. 3Sum 三数之和

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人公众号:负雪明烛 本文关键词:3sum, 三数之和,题解,leetcode, 力扣,P ...

  3. leetCode 15. 3Sum (3数之和) 解题思路和方法

    3Sum  Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find ...

  4. 【LeetCode 15】三数之和

    题目链接 [题解] 先把n个数字升序排个序. 然后枚举三元组最左边的那个数字是第i个数字. 之后用两个指针l,r移动来获取三元组的第2个和第3个数字. (初始值,l=i+1,r = n-1); 如果a ...

  5. [LeetCode] 3Sum 三数之和

    Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all un ...

  6. 【LeetCode】15、三数之和为0

    题目等级:3Sum(Medium) 题目描述: Given an array nums of n integers, are there elements a, b, c in nums such t ...

  7. LeetCode 第15题-三数之和

    1. 题目 2.题目分析与思路 3.思路 1. 题目 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且 ...

  8. LeeCode数组第15题三数之和

    题目:三数之和 内容: 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中 ...

  9. 【LeetCode每天一题】3Sum(三数之和)

    Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find ...

随机推荐

  1. 扩展centos7.4虚拟机磁盘大小

    虚拟机分配磁盘40GB,实际系统分区只用了20GB,需要手工扩展到40GB,操作方法如下: 查看磁盘信息(确认主分区只有17GB):[root@test-web1 ~]# df -hFilesyste ...

  2. java jdb

    https://stackoverflow.com/questions/8155253/how-do-i-compile-in-debug-mode-netbeans-java-maven <p ...

  3. 知识图谱与Bert结合

    论文题目: ERNIE: Enhanced Language Representation with Informative Entities(THU/ACL2019) 本文的工作也是属于对BERT锦 ...

  4. 最锋利的Visual Studio Web开发工具扩展:Web Essentials详解【转】

    Web Essentials是目前为止见过的最好用的VS扩展工具了,具体功能请待我一一道来. 首先,从Extension Manager里安装:最新版本是19号发布的2.5版 然后重启你的VS开发环境 ...

  5. SetApartmentState(ApartmentState state).Ensure that your Main function has STAThreadAttribute marked on it. This exception is only raised if a debugger is attached to the process

    System.Threading.ThreadStateException: 'Current thread must be set to single thread apartment (STA) ...

  6. WPF 动态资源 DataContext="{DynamicResource studentListKey}" DisplayMemberPath="Name"

    public class StudentList:ObservableCollection<Student> { public List<Student> studentLis ...

  7. C# winform打开新窗体显示一段时间 关闭新窗体

    1.form1的button事件下: form2 form = new form2(); form.Show(); Thread.Sleep(10000);  //form2窗体显示10秒 form. ...

  8. Python - MySQL 数据库连接 - PyMySQL 驱动 - 第二十五天

    序言 本文我们为大家介绍 Python3 使用 PyMySQL 连接数据库,并实现简单的增删改查. 什么是 PyMySQL? PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务 ...

  9. Python - 列表 - 第八天

    Python 列表 序列是Python中最基本的数据结构.序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推. Python有6个序列的内置类型,但最常见的 ...

  10. 转cocopods的使用

    一.概要 iOS开发时,项目中会引用许多第三方库,CocoaPods(https://github.com/CocoaPods/CocoaPods)可以用来方便的统一管理这些第三方库. 二.安装 由于 ...