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] 3Sum 三数之和的更多相关文章

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

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

  2. LeetCode:三数之和【15】

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

  3. [LeetCode] 15. 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 ...

  4. LeetCode 15. 三数之和(3Sum)

    15. 三数之和 15. 3Sum 题目描述 Given an array nums of n integers, are there elements a, b, c in nums such th ...

  5. 【LeetCode】三数之和【排序,固定一个数,然后双指针寻找另外两个数】

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

  6. Java实现 LeetCode 15 三数之和

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

  7. [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 ...

  8. LeetCode——15. 三数之和

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

  9. LeetCode 15. 三数之和(3Sum)

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

随机推荐

  1. windows环境tomcat8配置Solr5.5.1

    前言 前前后后接触Solr有一个多月了,想趁着学习Solr顺便把java拾起来.我分别用4.X和5.X版本在windows环境下用jetty的方式.tomcat部署的方式自己搭建了一把.其中从4.x到 ...

  2. 微信支付:H5吊起支付API,不显示“确认支付、输入密码”界面

    使用公众号进行支付,官方开发帮助文档: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1 其业务流程如下: 按照业务流程进行开发 ...

  3. Unity3d连接SQL Server数据库出现SocketException: 使用了与请求的协议不兼容的地址错误

    这两天,同学问我Unity3d连接SQL Server的问题,当时我只是简单的说:“应该一样吧,就是那简单的几句啊”.之后他让我试了下,我才发现有问题了.故此写下一篇博客,要牢记这件事的教训,操作数据 ...

  4. 何时使用静态 API

    看了<AutoMapper and the Static Class Debate>,记录一下自己的看法. 在进行API设计时,静态类的使用有时会为设计者带来一些烦恼.应该将某个函数暴露为 ...

  5. JavaScript弹窗

    警告框: alert("警告信息!"); alert("警告\n信息!"); 确认框: var t=confirm("请确认!"); // ...

  6. 设计模式(十三)代理模式(Proxy Pattern)

    一.引言 在软件开发过程中,有些对象有时候会由于网络或其他的障碍,以至于不能够或者不能直接访问到这些对象,如果直接访问对象给系统带来不必要的复杂性,这时候可以在客户端和目标对象之间增加一层中间层,让代 ...

  7. Android Studio同时打开多个项目

    Android Studio的默认设置是打开第二个项目时,第一个项目就被自动关闭了,如果要同时打开多个项目,可以点击File->Settings,对Project Opening进行下面的设置: ...

  8. 分金币 bzoj 3293

    分金币(1s 128M)  coin [问题描述] 圆桌上坐着n个人,每人有一定数量的金币,金币总数能被n整除.每个人可以给他左右相邻的人一些金币,最终使得每个人的金币数目相等.你的任务是求出被转手的 ...

  9. Java的Debug调试

    一.在项目上右键,Debug As>Debug on Server 二.在测试类上,Run As>Run On Server

  10. 记录一次bug解决过程:velocity中获取url中的参数

    一.总结 在Webx的Velocity中获取url中参数:$rundata.getRequest().getParameter('userId') 在Webx项目中,防止CSRF攻击(Cross-si ...