https://leetcode.com/problems/3sum/
Given an array
nums
of n integers, are there elements a, b, c innums
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] ]
我一开始理解错了题意,以为Node的意思是原始集合中的任何一个元素不能被使用两次,其实意思是最后的结果中不包含重复的三元组,这样一来问题就简单了很多。只需要先排序,然后针对原始数组中每一个值(注意重复元素算同一个值)固定下来,剩下的就变成了传统的两数和问题,从两边夹逼即可。
但是其中有很多小细节,比如如果被固定下来的第一个数就是正数的话,它右侧的数字必然都是正数,不可能存在满足要求的三元组,这是一个可以剪枝的地方。以及在找到解了之后怎么把他放到结果的vector<vector<int>>里,我一开始想的是emplace_back({..., ..., ...}),但是失败了不知道为什么,直接使用push_back({..., ..., ...})倒是可以。以及找到三元组之后两边界的移动和下一个固定首值的确定要跳过所有重复值。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
static int fast_io = []() { std::ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();
vector<vector<int>> result;
int len = nums.size();
if(len < 3) return result;
quick_sort(nums, 0, len-1);
int tem;
int lo, hi;
for(int i = 0; i < len-2; ++i){
if(i != 0 && nums[i] == nums[i-1]) continue;
tem = -nums[i];
if(tem < 0) break;
lo = i+1;
hi = len-1;
while(lo < hi){
if(nums[lo]+nums[hi] < tem){
++lo;
}else if(nums[lo]+nums[hi] > tem){
--hi;
}else{
//result.emplace_back({-tem, nums[lo], nums[hi]});
result.push_back({-tem, nums[lo], nums[hi]});
do{
++lo;
}while(lo < hi && nums[lo] == nums[lo-1]);
do{
--hi;
}while(lo < hi && nums[hi] == nums[hi+1]);
}
}
}
return result;
}
void quick_sort(vector<int>& nums, int lo, int hi){
if(lo >= hi) return;
int st = lo;
int ed = hi;
int tem = nums[st];
while(st < ed){
while(st < ed && nums[ed] >= tem) --ed;
nums[st] = nums[ed];
while(st < ed && nums[st] <= tem) ++st;
nums[ed] = nums[st];
}
nums[st] = tem;
quick_sort(nums, lo, st-1);
quick_sort(nums, st+1, hi);
}
};