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] ]
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
if(nums.size() <=2) return {};
vector<vector<int> > ans;
sort(nums.begin(), nums.end());
for(int i =0; i < nums.size();){
int start = i+1, end = nums.size()-1;
while(start < end){
if(nums[i]+nums[start]+nums[end] == 0){
ans.push_back({nums[i],nums[start],nums[end]});
start++;
end--;
while((start < end) && nums[start] == nums[start-1]) start++;
while((start < end) && nums[end] == nums[end+1]) end--;
}else if(nums[i]+nums[start]+nums[end]<0){
start++;
while((start < end) && nums[start] == nums[start-1]) start++;
}else{
end--;
while((start < end) && nums[end] == nums[end+1]) end--;
}
}
i++;
while((i < nums.size()) && nums[i] == nums[i-1])
i++;
}
return ans;
}
};
当然,排序还是得要有的。
既然这样不行的话,就要换另一种思路了,得把复杂度降下来,既然3层循环加优化都不行,那么就只有2层循环了。我的思路是这样的,先定下第一个数,第二个数为第一个数的下一位,第三个数为序列的最后一位。第一个数不动,第二个数和第三个数分别往中间靠拢,直到第二个数的序列号大于等于第三个数时为止。简易的图如下:
1 2→→→ ←←←3
接下来就是什么时候第二、三个数要往中间靠拢了。当a1 + a2 + a3 = 0时,(这里的a1、a2、a3表示第1-3个数),这表示已经找到符合题意的3个数了,需要寻找下一组数,这时a2和a3都要往中间靠拢一步。当a1 + a2 + a3 > 0时,说明a3太大了,需要更小一些的,所以此时a3往中间靠拢一步。当a1 + a2 + a3 < 0时,说明a2太小了,需要更大一些的,所以此时a2往中间靠拢一步。
这样大致就差不多了,还需要注意一点就是不能出现重复的结果。每当a1a2a3移位后,就要判断其是否和上一位是否相等,如果相等,继续移位,直到不相等为止。