Given an array nums of n integers, are there elements a, b, c in nums 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.
Example:
Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
这道题让我们在数组内找三个和为0的数,要求找到的三个数不能重复。
我一开始看到就想到2sum的问题,fix一个数target,然后找另外两个数使得他两之和为-target。我的写法是用一个set记录数组的元素,然后双循环数组求两数之和,当和为-target,加入结果集,当然加之前先做个判断,是否在结果集已经有了。复杂度差不多是0(N^2),结果还是超时了。
翻阅大佬的博客,看完后赏心悦目,优秀的解法用到了双指针操作。首先对数组排序,然后再找数字可以起到有效剪枝的效果。遍历数组,每次fix住一个数target,当target为正数,那直接退出,因为排完序后的数组后面的数肯定比target大,那不可能存在两数之和为负了。在具体找另外两个数之前还要对fix的数做个去重,如果target和相邻的数相等,那么直接将fix数的指针右移。然后就是找另外两数了,找另外两个数的时候也需要做类似的操作来去重,话不多说,还是代码说的更清楚。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
int i,j;
sort(nums.begin(),nums.end());
if(nums.size()<3||nums.front()>0||nums.back()<0) return res;
for (int k=0;k<nums.size();k++)
{
//去掉重复fix住的数
while (k > 0 && k<nums.size() && nums[k]==nums[k-1]) k++;
if (k < 0 || k >= nums.size()) break;
int target = -nums[k];
// 若target为负,说明nums[i]为正,那么说明i之后的都为正数,不可能为负数
if (target<0) break;
i=k+1;
j=nums.size()-1;
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+1]) i++;
while(i<j&&nums[j]==nums[j-1]) j--;
i++;
j--;
}
else if (nums[i] + nums[j] < target) i++;
else j--;
}
}
return res;
}
};