题目描述
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
出处
思路
把三数之和转化为两数之和,首先建立两数和的哈希表,然后遍历一遍找。
但是会超时,即使构建时控制key的范围为nums的子集,在set去重时仍会超时。
所以正确解法应该用双指针,这里两个方法都贴上。
代码
//超时308/312
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
//构建哈希表
unordered_map<int, vector<vector<int>>> hash;
int max = *max_element(nums.begin(), nums.end());
int min = *min_element(nums.begin(), nums.end());
for(int j = 0; j < nums.size()-1; j++)
for(int k = j+1; k < nums.size(); k++){
if(-nums[j]-nums[k]>=min&&-nums[j]-nums[k]<=max)
hash[nums[j]+nums[k]].emplace_back(vector<int>{j, k});
}
set<vector<int>> ans; //保证不重复
for(int i = 0; i < nums.size(); i++){
if(hash.find(-nums[i]) != hash.end()){
for(int j=0;j<hash[-nums[i]].size();j++){
vector<int> a = hash[-nums[i]][j];
if(i==a[0]||i==a[1])
continue;
a[0]=nums[a[0]];
a[1]=nums[a[1]];
a.push_back(nums[i]);
sort(a.begin(), a.end());
ans.insert(a);
}
}
}
vector<vector<int>> res;
res.assign(ans.begin(), ans.end());
return res;
}
};
//正解
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
int n = nums.size();
for(int i = 0; i < nums.size()-2; i++){
if(nums[i] + nums[n-2] + nums[n-1] < 0||(i>0 && nums[i]==nums[i-1]))
continue;
if(nums[i]>0)
break;
int l = i + 1, r = nums.size() - 1;
while (l < r) {
if (nums[l] + nums[r] + nums[i] < 0) ++l;
else if (nums[l] + nums[r] + nums[i] > 0) --r;
else {
ans.push_back({nums[i], nums[l], nums[r]});
++l, --r;
while (l < r && nums[l] == nums[l - 1]) ++l;
while (l < r && nums[r] == nums[r + 1]) --r;
}
}
}
return ans;
}
};