问题
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)
代码
typedef struct node_s{
int leftIndex;
int rightIndex;
int twoSum;
}node;
bool compileM(const int &a , const int &b)
{
return a < b;
}
class Solution {
public:
vector<vector<int> > fourSum(vector<int> &num, int target) {
map<int, list<node>* >mymap;
vector<vector<int> > resultV;
if (num.size() < 4) {
return resultV;
}
vector<int> temp(num);
sort(temp.begin(), temp.end(), compileM);
/* create a map O(N^2)*/
for (int i = 0 ; i < temp.size(); i++) {
for (int j = i+1 ; j < temp.size(); j++) {
node myNode;
myNode.leftIndex = i;
myNode.rightIndex = j;
myNode.twoSum = temp[i] + temp[j];
list<node>* mylist = mymap[ temp[i] + temp[j]];
if (!mylist) {
mylist = new list<node>;
mymap[ temp[i] + temp[j]] = mylist;
}
mylist->push_back(myNode);
}
}
map<int, list<node>* >::iterator beginiter = mymap.begin();
map<int, list<node>* >::iterator enditer = mymap.end();
#if 1
for (; beginiter != enditer; beginiter++) {
list<node>* rightList = mymap[target - beginiter->first];
if (!beginiter->second) {
continue;
}
if (rightList && rightList->size() > 0)
{
/* equal */
list<node>* leftList = beginiter->second;
for (list<node>::iterator leftListIter = leftList->begin() ; leftListIter !=leftList->end();leftListIter ++) {
for (list<node>::iterator rightListIter = rightList->begin(); rightListIter != rightList->end(); rightListIter ++) {
node node1 = *leftListIter;
node node2 = *rightListIter;
if (node1.leftIndex != node2.leftIndex && node1.leftIndex != node2.rightIndex &&
node1.rightIndex != node2.leftIndex && node1.rightIndex != node2.rightIndex &&
node1.leftIndex < node2.leftIndex) {
int tempA[4];
tempA[0] = temp[node1.leftIndex];
tempA[1] = temp[node1.rightIndex];
tempA[2] = temp[node2.leftIndex];
tempA[3] = temp[node2.rightIndex];
vector<int> tempv(tempA,tempA+4);
sort(tempv.begin(), tempv.end(), compileM);
int kk =0;
for (kk = 0; kk < resultV.size(); kk++) {
if(resultV[kk][0] == tempv[0] &&
resultV[kk][1] == tempv[1] &&
resultV[kk][2] == tempv[2] &&
resultV[kk][3] == tempv[3])
{
break;
}
}
if (kk == resultV.size()) {
resultV.push_back(tempv);
//cout<<tempv[0] << ","<<tempv[1] <<"," <<tempv[2]<<","<<tempv[3]<<endl;
}
}
}
}
}
}
#endif
return resultV;
}
};
分析
这里利用了map,这里的map当然可以换成hash_map咯。这里解释一下实现的思想。
使用map存下来所有两两相加的结果,并存入到链表中。
遍历整个map,并寻找出 target-a 的值是否有这样的节点(链表不为空)。
存在,则遍历整个链表,因为刚开始保存了所有的i,j,这样四个数只要保证没有重复计算某个下表,则这个四位数是可以接受的。(注意一个细节,遍历的 node 的小下表必须 < 找到的node的最小下表,理由是必须向后找,否则想前找会找到重复的组合)
然后排序这四个数,推入到vector中,完事。
时间复杂度是 O(N^2) + O(N) = O(N^2)。空间复杂度也是 O(N^2)。
分析2
利用3sum的解法,先把问题分解成 3sum, 然后 2sum。。。
最后的复杂度比 3sum 多一次遍历,则复杂度是 O(N^3) , 但是空间没有损耗。
总结
各有优劣,被问到 如何使用O(N^2) 来实现4sum,貌似可以被问到。