LeetCode 15. 3Sum
问题链接
题目解析
给定n个元素的数组,寻找符合 \(a+b+c=0\) 的所有 {a, b, c}。
解题思路
如果对LeetCode的第一题Two Sum 还有印象的话,会发现这道题很类似,不过题目要求的结果有明显区别,本题需要求出所有符合条件的结果。
如果想复用Two Sum中的方法,可以加以转化:\(a+b = -c\),与 \(x+y = target\)就很类似了。存在一个严重的问题——重复的结果!为了避免重复,可以想到需用使用 \(set\) 容器。由于 \(set\) 中的元素是三元素向量,想要避免重复必须使向量中三个元素有序,所以需要先将数组排序。
参考代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
set<vector<int>> res;
sort(nums.begin(), nums.end());
for (int k = 0; k < nums.size(); k++) {
if (nums[k] > 0) break;
int target = 0 - nums[k];//固定最小数
int i = k + 1, j = nums.size() - 1;
while (i < j) {
if (nums[i] + nums[j] < target) ++i;
else if (nums[i] + nums[j] > target) --j;
else {
res.insert({nums[k], nums[i], nums[j]});
++i; --j;
}
}
}
return vector<vector<int>>(res.begin(), res.end());
}
};
方法改进
上述代码需要300+ms,太慢了,仔细想想,其实不用 \(set\) 容器也可以做到,先将数组排序,遍历每个数字,即先确定最小的数字,寻找另外两个数,避免重复只需要跳过相等的数字(位于相邻位置)即可。思路一模一样,这其实是对上一方法的简化,因为二者都需要排序,而排好序后相等的数字必然在相邻位置,开直接排序,不需要 \(set\)。这种改进方法只要100+ms,快了不止一点点~
参考代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
for (int k = 0; k < nums.size(); k++) {
if (nums[k] > 0) break;
if (k > 0 && nums[k] == nums[k - 1])//避免重复
continue;
int target = 0 - nums[k];//固定最小数
int i = k + 1, j = nums.size() - 1;
while (i < j) {
if (nums[i] + nums[j] < target) ++i;
else if (nums[i] + nums[j] > target) --j;
else {
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;
}
}
}
return res;
}
};
相似题目
LeetCode 1. Two Sum
LeetCode 16. 3Sum Closest
LeetCode 18. 4Sum
LeetCode All in One题解汇总(持续更新中...)
本文版权归作者AlvinZH和博客园所有,欢迎转载和商用,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.