题目:
Given an array S of n integers, are there elements a,b,c, and d in S such that a+b+c+d = target?
Find all unique quadruplets in the array which gives the sum of target.
Note:
? Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
? The solution set must not contain duplicate quadruplets.
For example, given array S = {1 0 -1 0 -2 2}, and target = 0.
A solution set is:
(-1, 0, 0, 1)
(-2, -1, 1, 2)
(-2, 0, 0, 2)
分析:给定一个包含n个数的数组,问是否在数组中存在四个数abcd,使得a+b+c+d = target。在数组中找出所有的符合条件的四个数的集合。要求每个集合不重复,并且abcd从小到大排列。方法三种:
1.先排序,然后左右夹逼,时间复杂度 O(n^3),空间复杂度 O(1)
2.先排序然后缓存两个数的和,最后,遍历。
3.先排序,然后缓存两个数的和,然后对这些和进行2sum。要求坐标不等。
代码:
#include "stdafx.h" #include <ctime>
#include <iostream> #include <vector> #include <algorithm> #include <unordered_map> using namespace stdext; using namespace std;
class Solution{ public: vector< vector<int> > FourSum1(vector<int>& num, int target){ vector<vector<int>> result; vector<int> temp(4); sort(num.begin(),num.end()); auto last = num.end(); for (auto a = num.begin();a != last - 3;++a){ for(auto b = next(a);b != prev(last,2);++b){ auto c = next(b); auto d = prev(last); while(c < d){ if (*a + *b + *c + *d < target){ c++; } else if (*a + *b + *c + *d >target){ d--; }else{ temp[0]=*a; temp[1]=*b; temp[2]=*c; temp[3]=*d; result.push_back(temp); ++c;--d; } } } } sort(result.begin(), result.end()); //unique移除相邻重复的元素,然后返回的是新的结尾指针,erase擦除多余的内存部分。 result.erase(unique(result.begin(),result.end()), result.end()); return result; } vector< vector<int> > FourSum2(vector<int>& num, int target){ vector<vector<int>> result; if (num.size() < 4) return result; vector<int> temp(4); sort(num.begin(),num.end()); unordered_map<int, vector<pair<int, int>> > twoSum; //重复的键值,将其存放在一个vector中 auto last = num.end(); for (size_t a=0;a<num.size();++a){ for (size_t b = a+1;b<num.size();++b){ twoSum[num[a] + num[b]].push_back(pair<int,int>(num[a],num[b])); } } int sub = 0; for(size_t c=0;c<num.size();++c){ for (size_t d=c+1;d<num.size();++d){ sub = target - num[c] - num[d]; if(twoSum.find(sub) == twoSum.end()) continue; auto& subRst = twoSum[sub];//可能有多个结果。 for (size_t i=0;i<subRst.size();++i){ if(num[c] <= subRst[i].first || num[d] <= subRst[i].second) //去除重复的情况,pair中的元素从小到大排序,所以second continue; temp[0] = subRst[i].first; temp[1] = subRst[i].second; temp[2] = num[c]; temp[3] = num[d]; sort(temp.begin(),temp.end()); result.push_back(temp); } } } sort(result.begin(), result.end()); result.erase(unique(result.begin(),result.end()), result.end()); return result; } vector< vector<int> > FourSum3(vector<int>& num, int target){ vector<vector<int>> result; if (num.size() < 4) return result; vector<int> temp(4); sort(num.begin(),num.end()); unordered_multimap< int,pair<int, int> > twoSum; for(size_t i = 0;i<num.size();++i){ for (size_t j=i+1;j<num.size();++j){ twoSum.insert(make_pair(num[i]+ num[j], make_pair(num[i],num[j]))); } } for(auto i=twoSum.begin();i!=twoSum.end();++i){ int sub = target - i->first; auto range = twoSum.equal_range(sub); for(auto j=range.first;j!=range.second;++j){ pair<int,int> k = i->second; int a = k.first ; int b = k.second; int c = j->second.first; int d = j->second.second; if(a!=c && a!=d && b != c && b!=d){ temp[0] = a; temp[1] = b; temp[2] = c; temp[3] = d; sort(temp.begin(),temp.end()); result.push_back(temp); } } } sort(result.begin(), result.end()); result.erase(unique(result.begin(),result.end()), result.end()); return result; } }; int _tmain(int argc, _TCHAR* argv[]) { vector<int> v1; vector<vector<int>> result; v1.push_back(1); v1.push_back(0); v1.push_back(-1); v1.push_back(0); v1.push_back(-2); v1.push_back(2); //v1.push_back((rand()%200 - 100));v1.push_back((rand()%200 - 100)); Solution s; clock_t start,finish; long i = 100000L; double duration; start = clock(); result = s.FourSum1(v1,0); finish = clock(); duration = (double)(finish - start)/CLOCKS_PER_SEC; cout<< "FourSum1 Runtime:" << duration << endl; start = clock(); result = s.FourSum2(v1,0); finish = clock(); duration = (double)(finish - start)/CLOCKS_PER_SEC; cout<< "FourSum2 Runtime:" << duration << endl; start = clock(); result = s.FourSum3(v1,0); finish = clock(); duration = (double)(finish - start)/CLOCKS_PER_SEC; cout<< "FourSum3 Runtime:" << duration << endl; return 0; }
小结:
很值得研究的一道题目,建议自己写一遍,不仅对算法思想提升有帮助,而且在使用stl的学习上,也是有帮助的。根据我测试,就运行时间来说,方法一最快,二其次,三最慢。
另外,方法二实验unordered_map,其中key值相同的话,相同的key的value保存在一个vector桶中。而方法三使用unordered_multimap,当存在key相同的情况,并不是像前者那样存储,而是分开存储。
比如:unordered_map中形式如: [1] = (-2, [2]((-2, 0),(-2, 0))) 相同的键值都放在一起。不允许重复的键值。
unordered_multimap中 形式如:(-2, (-2, 0)),(-2, (-2, 0)) 虽然键值不一样,但是都是分开存放的。允许重复的键值。