Given an array S of n integers, are there elements a, b, c 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)
这道题是找出数组中相加和是0的三元组,题目难度为Medium。
三层循环遍历的方法就不说了,估计会超时。接下来要考虑的问题是要不要排序,不排序的话三元组还不能重复,处理起来比较麻烦,因此我们首先把数组排序,这样后续处理会方便很多。排序之后固定第一个数字,然后分别从前后两端(前端从第一个数字的下一个数字开始)再取两个数字相加,如果是正数,表明相加和大了,第三个数字取其前面的数字再判断,如果相加和是负数则第二个数字取其后面的数字再判断,直至相加和是0,此时就找到了一个三元组,之后第二个数字取其后面的数字同时第三个数字取其前面的数字继续循环。相加和是0的情况还需要判断三元组是否重复,进行简单查找判重之后提交了代码,超时了!
有哪些地方能够优化呢?首先想到的是第一个数字的选取,在最外层循环中,如果当前遍历的第一个数字和之前的相等,那这轮循环就可以跳过了,因为即使出现满足条件的三元组也是重复的。这样并不能完全避免重复三元组的出现,但是我们可以采用相同的方法来处理后面两个数字,在出现满足条件的三元组时,我们对第二个数字和第三个数字进行判断,如果移动之后的数字和之前的相等,就继续移动,直至出现不同的数字,这样是否就完全避免了重复三元组的出现?经过处理,第一个数字不会重复,固定第一个数字之后,后两个数字也不会重复,因此满足条件的三元组不会重复,这样就避免了查找。提交代码,通过!具体代码:
class Solution {
public:
vector<vector<int> > threeSum(vector<int> &num) {
vector<vector<int>> rst;
if(num.size() < 3) return rst;
sort(num.begin(), num.end());
for(int i=0; i<num.size()-2; i++) {
if(i > 0 && num[i] == num[i-1]) continue;
for(int j=i+1, k=num.size()-1; j<k;) {
int sum = num[i] + num[j] + num[k];
if(sum < 0) {
j++;
}
else if(sum > 0) {
k--;
}
else {
vector<int> curRst;
curRst.push_back(num[i]);
curRst.push_back(num[j]);
curRst.push_back(num[k]);
rst.push_back(curRst);
do {j++;} while(num[j] == num[j-1] && j < k);
do {k--;} while(num[k] == num[k+1] && j < k);
}
}
}
return rst;
}
};