2.3个数之和
给定 n n n 个整数的一个数组 S S S. S S S 中是否有元素 a a a、 b b b 和 c c c 满足a+b+c=0
? 找出数组中所有满足加和为 0
的不同的三个数组合。
注意,(a,b.c)
中的元素必须是非降序的排列方式(即, a ≤ b ≤ c a≤b≤c a≤b≤c)。
解决方案中给出的集合不能包含重复的三元组。
例如,给定数组S = { -1 0 1 2 -1 -4}
一个解决方案集合是
(-1,0,1)
(-1,-1,2)
【解析】
这是上一题的扩展,把2个变量变成3个变量。对于一般的扩展题,要通过一些转化将其还原为已有的问题,才能更好地处理。
如果我们把等式稍稍修改一下,
a + b + c = 0 => a + b = -c
这时候,问题就转换为,寻找两个变量 a a a 和 b b b ,使得其之和为 − c -c −c ,又回到了“两数之和”的问题。
因为题目提到了可能出现重复解的问题,所以要注意“去重”。
1.代码第 19~24行
双指针扫描的去重。例如,对于[-2,0,0,2,2]
,我们期待的结果应该
是[-2,0,2]。如果不去重的话,结果就是[-2,0,2]
,[-2,0,2]
2.代码第37行
外层循环去重。比如[-2,-2,-2,0,2]
,包含三个-2
,当在循环中处理完第一个-2
以后,后面的两个就没有必要重复处理了。
【代码】
#include<bits/stdc++.h>
using namespace std;
vector<vector<int>> threeSum(vector<int> &num){
std::sort(num.begin(), num.end());
vector<vector<int>> result;
int len =num.size();
for (int i = 0; i < len;i++){
int target = 0 - num[i];
int start = i + 1, end = len - 1;
while(start<end){
if(num[start]+num[end]==target){
vector<int> solution;
solution.push_back(num[i]);
solution.push_back(num[start]);
solution.push_back(num[end]);
result.push_back(solution);
start++;
end--;
while(start<end&&num[start]==num[start-1])
start++;
while(start<end&&num[end]==num[end+1])
end--;
}
else if(num[start]+num[end]<target)
start++;
else
end--;
}
if(i<len-1)
while(num[i]==num[i+1])
i++;
}
return result;
}
int main(){
vector<int> numbers = {
-1, 0, 1, 2, -1, -4};
vector<vector<int>> result = threeSum(numbers);
for (int i = 0; i < result.size();i++){
for (int j = 0; j < result[i].size();j++)
printf("%2d ",result[i][j]);
printf("\n");
}
return 0;
}