本题的要求是在一个输入列表里找出所有三个数加起来等于0的组合。
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: 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]
]
观察知道,输入列表是无序的,而由于无序的原因,我们必须是要轮询三遍的,因为永远不知道下一个值是什么值,正值或者是负值。
那么为了能够增加我们的可用信息,因此我们第一步是先排序。
第二步,我们发现,排好序了以后,就要着手找sum=0的组合。而三个数的组合可以简化成两个两个数的组合。也就是
3sum = 2sum + 2sum
那么,我们的具体做法就是,从左到右,依次取定第一个数。之后,我们在它之后的剩余数中寻找两个加起来等于这个数的相反数的数对。这就变成了leetcode的1号算法题,2sum了。
回想2sum是怎么做的:
1.排序
2.front和back双指针分别向中间收缩,如果和小于target,那么front向后,如果和大于target,那么back向前,搜索至front==back位置,若找到,则记录结果,并继续向前。
好了,第一次2sum这个子问题解决了之后,我们需要解决的是第二次2sum
还有一个信息我们没用上,就是3sum的target固定是0!
那么,当我们从左向右取定第一个数的时候,就只需要遍历负数或者整数vector,而不需要遍历全部的vector!
附上cpp代码:
class Solution {
public:
vector<vector<int>> twoSum(vector<int>& nums, front, back, target) {
# 做2Sum算法
vector<vector<int>> res;
while (front < back) {
int sum = nums[front] + nums[back];
if (sum < target)
front++;
else if (sum > target)
back--;
else {
vector<int> triplet(3, 0);
triplet[0] = -target;
triplet[1] = nums[front];
triplet[2] = nums[back];
res.push_back(triplet);
// 去重复
while (front < back && nums[front] == triplet[1]) front++;
while (front < back && nums[back] == triplet[2]) back--;
}
}
return res;
}
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int> > res;
std::sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++) {
int target = -nums[i];
int front = i + 1;
int back = nums.size() - 1;
vector<vector<int>> temp = twoSum(nums, front, back, target);
for (i = 0; i < temp.size(); i++) {
res.push_back(temp[i]);
}
// 去重复
while (i + 1 < nums.size() && nums[i + 1] == nums[i])
i++;
}
return res;
}
};