基本的 穷举前面的数的组合+后两个数夹逼法的算法:O(n^3):
1)排序
2)主循环穷举前两个数的组合,保证数组至少剩下2个数(i=0,i<n-3, j=i+1, j<n-2),注意去重,为什么可以跳过去?因为i,j当前取值下的剩余数组是之前取值下剩余数组的子数组,如果i, j的值之前有过,那么当前i,j下的解已经包含了。
3) 数组剩余部分应用两头夹逼法。注意去重
vector<vector<int> > fourSum(vector<int> &num, int target) {
vector<vector<int>> output;
int n = num.size();
if(n<4) return output;
sort(num.begin(),num.end());
for(int i=0;i<n-3;i++)
{
if(i!=0 && num[i]==num[i-1])
continue;
for(int j=i+1;j<n-2;j++)
{
if(j!=i+1 && num[j]==num[j-1])
continue;
int begin = j+1, end = n-1;
while(begin<end)
{
int sum = num[i] + num[j] + num[begin] + num[end];
if(sum== target)
{
vector<int> v;
v.push_back(num[i]);v.push_back(num[j]);v.push_back(num[begin]);v.push_back(num[end]);
output.push_back(v);
begin++; end--;
while(begin<end && num[begin]==num[begin-1])
begin++;
while(begin<end && num[end]==num[end+1])
end--;
}
else if(sum< target)
begin++;
else
end--;
}
}
}
return output;
}
借助map 的 O(n*n)算法,不需要排序,总体思路和2Sum的Map解法类似。 第一个O(n*n) 循环先用map缓存前两个数a,b组合的和,第二个O(n*n)循环枚举后两个数c,d,判断sum-c-d是否在map中。保证下标c,d 在 a, b之后。
vector<vector<int> > fourSum(vector<int> &num, int target) {
vector<vector<int>> output;
int n = num.size();
if(n<4) return output;
sort(num.begin(),num.end());
unordered_map<int,vector<pair<int,int>>> map;
for(int i=0;i<n-3;i++)
{
if(i!=0 && num[i]==num[i-1])
continue;
for(int j=i+1;j<n-2;j++)
{
if(j!=i+1 && num[j]==num[j-1])
continue;
map[num[i]+num[j]].push_back(pair<int,int>(i,j));
}
}
for(int i=2;i<n-1;i++)
{
for(int j=i+1;j<n;j++)
{
if(j!=i+1 && num[j]==num[j-1])
continue;
int x = target-num[i]-num[j];
if(map.find(x)==map.end())
continue;
for(auto it= map[x].begin();it<map[x].end();it++)
{
if((*it).second<i)
{
int a[]={num[(*it).first],num[(*it).second],num[i],num[j]};
output.push_back(vector<int>(a,a+4));
}
}
}
}
sort(output.begin(),output.end());
output.erase(unique(output.begin(),output.end()),output.end());
return output;
}