问题描述
给定一个数组arr,以及一个数字target。求数组中和为target的三个数。要求给出所有解。数组中的每个数在每组解中只能出现一次。
解法
方法一:如果用暴力方法,时间复杂度是 o(n3)
方法二:利用C++11中的unordered_multimap,本题复杂度可降至 O(n2)
#include<iostream>
#include<vector>
#include<unordered_map>
#include <set>
#include <algorithm>
using namespace std;
class Solution {
public:
vector<vector<int> > threeSum(vector<int> &num, int sum) {
unordered_multimap<int, int> hashmap;
vector<vector<int> > result;
for(int i=num.size()-1; i>=0; i--)
{
hashmap.insert( {num.at(i), num.size()-i-1} );
}
/*
for(auto iter1=hashmap.begin(); iter1!=hashmap.end(); iter1++)
{
cout<<(*iter1).first<<" ";
cout<<(*iter1).second<<endl;
}
cout<<endl;
*/
for(auto iter1=hashmap.begin(); iter1!=hashmap.end(); iter1++)
{
int target = sum -(*iter1).first;
auto iter = iter1;
iter++;
if (iter == hashmap.end() )
continue;
for(auto iter2=iter; iter2!=hashmap.end(); iter2++)
{
auto iterres = hashmap.equal_range( target - (*iter2).first );
if (iterres.first == iterres.second)//下界pair和上界pair相等,没找到
{
continue;
}
for(auto get=iterres.first; get!=iterres.second; get++)
{
//get遍历所有pair(一对mapiterator),(*get)取出一个pair,(*get).second表示第二个map变量
//if (get == hashmap.end() || (*iter1).second >= (*iter2).second || (*iter2).second >= (*get).second )
if (get == hashmap.end() || (*iter1).second == (*iter2).second || (*iter2).second == (*get).second || (*iter1).second == (*get).second ) //后面三个都不能遗漏!
{
continue;
}
int res = (*get).first;
int arr[] = { (*iter2).first, (*iter1).first, res};
sort(arr, arr+3);
vector<int> trip(arr, arr+3);
result.push_back(trip);
}
}
}
set< vector<int> > tmpres;
for(int i=0; i<result.size(); i++)
{
tmpres.insert( result.at(i) );
}
result.clear();
for(auto iter=tmpres.begin(); iter!=tmpres.end(); iter++)
{
result.push_back( *iter );
}
return result;
}
};
int main()
{
Solution sol;
//int arr[] = {-1, 0, 1, 2, -1, -4};
int arr[] = {7,5,-8,-6,-13,7,10,1,1,-4,-14,0,-1,-10,1,-13,-4,6,-11,8,-6,0,0,-5,0,11,-9,8,2,-6,4,-14,6,4,-5,0,-12,12,-13,5,-6,10,-10,0,7,-2,-5,-12,12,-9,12,-9,6,-11,1,14,8,-1,7,-13,8,-11,-11,0,0,-1,-15,3,-11,9,-7,-10,4,-2,5,-4,12,7,-8,9,14,-11,7,5,-15,-15,-4,0,0,-11,3,-15,-15,7,0,0,13,-7,-12,9,9,-3,14,-1,2,5,2,-9,-3,1,7,-12,-3,-1,1,-2,0,12,5,7,8,-7,7,8,7,-15};
vector<int> num(arr, arr+200);
vector<vector<int> > res = sol.threeSum(num, 10);
for(int i=0; i<res.size(); i++)
{
for(int j=0; j<res.at(i).size(); j++)
{
cout<<res.at(i).at(j)<<" ";
}
cout<<endl;
}
return 0;
}
以上解法(稍加修改),提交给leetcode(第15题)后仍然报错(Time Limit Exceeded)。难道有更低复杂度的解法吗?
希望有高手能指点一二。
方法三:先排序,然后二分查找,复杂度可降至 O(nlogn)
vector<vector<int> > threeSum(vector<int> &num)
{
vector<vector<int> > res;
if(num.empty())
return res;
sort(num.begin(), num.end()); //nlogn
for(int i=0; i+2<num.size(); i++) //n
{
if(i>0 && num[i] == num[i-1])
continue;
int left(i+1), right(num.size()-1);
while(left < right)//logn
{
if(left>i+1 && num[left] == num[left-1])
{
left++;
continue;
}
if(right < num.size()-1 && num[right] == num[right+1])
{
right--;
continue;
}
int sum = num[i] + num[left] + num[right];
if(sum < 0) left++;
else if(sum > 0) right--;
else
{
res.push_back( vector<int> {num[i], num[left], num[right]} );
right--;
left++;
}
}
}
return res;
}
同理,如果需要查找数组中和为某给定值的四元组,用法三解决,时间复杂度为 O(n2logn)