题目大意
给定一个数组,要求在这个数组中找出 3 个数之和为 0 的所有组合
解题思路
用 map 提前计算好任意 2 个数字之和,保存起来,可以将时间复杂度降到 O(n^2)。这一题比较麻烦的一点在于,最后输出解的时候,要求输出不重复的解。数组中同一个数字可能出现多次,同一个数字也可能使用多次,但是最后输出解的时候,不能重复。例如 [-1,-1,2] 和 [2, -1, -1]、[-1, 2, -1] 这 3 个解是重复的,即使 -1 可能出现 100 次,每次使用的 -1 的数组下标都是不同的。
这里就需要去重和排序了。map 记录每个数字出现的次数,然后对 map 的 key 数组进行排序,最后在这个排序以后的数组里面扫,找到另外 2 个数字能和自己组成 0 的组合。
假设输入数组是 S[0…n-1],3SUM 平均可以在 O(n^2) 时间内解决将每个数字 S[i] 插入一个哈希表,然后对于每个索引 i 和 j,检查哈希表是否包含整数 - (s[i]+s[j])
或者,下面的算法首先对输入数组进行排序,然后测试所有以仔细的顺序排列可能的对,避免需要对对进行二分搜索在排序列表中,实现最坏情况 O(n^n)
#include <stdio.h>
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
vector<vector<int> > threeSum(vector<int> &num)
{
vector<vector<int>> result;
if(num.size() == 0 || num.size() == 1||num.size() == 2) return result;
//对数组进行排序,这是关键
sort(num.begin(),num.end());
int n = num.size();
for(int i = 0;i < n - 2;i++)
{
//跳过重复
if(i > 0 && num[i - 1] == num[i]) continue;
int a = num[i];
int low = i + 1;
int high = n - 1;
while(low < high)
{
int b = num[low];
int c = num[high];
if(a+b+c == 0)
{
//得到解决方案
vector<int> v;
v.push_back(a);
v.push_back(b);
v.push_back(c);
result.push_back(v);
//继续搜索总和为零的所有三元组组合。
//跳过重复
while(low < n - 1 && num[low] == num[low + 1]) low++;
while(high > 0 && num[high] == num[high - 1]) high--;
low++;
high--;
}
else if(a + b + c > 0)
{
//跳过重复
while(high > 0 && num[high] == num[high - 1]) high--;
high--;
}
else
{
//跳过重复
while (low < n - 1 && num[low] == num[low + 1]) low++;
low++;
}
}
}
return result;
}
void printMatrix(vector<vector<int>> &matrix)
{
for(int i = 0;i < matrix.size();i++)
{
printf("{");
for(int j = 0;j < matrix[i].size();j++)
{
printf("%3d",matrix[i][j]);
}
printf("}\n");
}
cout<<endl;
}
int main()
{
int a[] = { -1, 1, 1, 1, -1, -1, 0,0,0 };
vector<int>n(a,a+sizeof(a)/sizeof(int));
vector<vector<int>> result = threeSum(n);
printMatrix(result);
return 0;
}