Leetcode:四和

时间:2014-08-05 15:04:33

标签: arrays algorithm sum

问题:给定n个整数的数组S,S中是否有元素a,b,c和d,使得a + b + c + d =目标?找到数组中所有唯一的四元组,它们给出了目标的总和。

注意: 四元组(a,b,c,d)中的元素必须以非降序排列。 (即a≤b≤c≤d) 解决方案集不得包含重复的四元组。

例如,给定数组S = {1 0 -1 0 -2 2},目标= 0。

A solution set is:
(-1,  0, 0, 1)
(-2, -1, 1, 2)
(-2,  0, 0, 2)

我知道这个问题有一个O(n ^ 3)解决方案,但我想知道是否有更快的算法。我搜索了很多,发现许多人给出了一个O(n ^ 2logn)解决方案,当S中存在重复的对数时,它无法正确处理案例(如herehere)。我希望有人可以给我一个正确版本的O(n ^ 2logn)算法,如果它确实存在的话。

谢谢!

3 个答案:

答案 0 :(得分:2)

蛮力算法花费时间O(n ^ 4):使用四个嵌套循环来形成输入中四个项目的所有组合,并将任何总和保留到目标。

一个简单的改进需要时间O(n ^ 3):使用三个嵌套循环来形成输入中三个项目的所有组合,并将任何总和保持为目标的负数。

我所知道的最好的算法是中间相遇算法,该算法在时间O(n ^ 2)内运行:使用两个嵌套循环从输入中形成两个项目的所有组合,将对和总数存储在由total索引的某种字典(哈希表,平衡树)中。然后使用两个以上的嵌套循环再次从输入中形成两个项目的所有组合,并保留嵌套循环中的两个项目,加上字典中的两个项目,对于任何一对项目总和为负数字典。

我的代码位于my blog

答案 1 :(得分:0)

恕我直言,对于O(n ^ 2lgn)算法,在创建aux[]数组时可以解决重复问题。 (我在你提供的第二个链接中使用了该名称)。基本思想是首先对输入中的元素进行排序,然后在处理数组时跳过重复项。

vector<int> createAuxArray(vector<int> input) {
  int len = input.size();
  vector<int> aux;

  sort(input.begin(), input.end());

  for (int i = 0; i < len; ++i) {
    if (i != 0 && input[i] == input[i - 1]) continue; // skip when encountered a duplicate

    for (int j = i + 1; j < len; ++j) {
      if (j != i + 1 && input[j] == input[j - 1]) continue; // same idea

      aux.push_back(createAuxElement(input[i], input[j]); 
    }
  }
  return aux;
}

此模块的复杂度为O(nlgn)+ O(n ^ 2)= O(n ^ 2),这不会影响整体性能。创建aux数组后,我们可以将其插入帖子中提到的代码中,结果将是正确的。

请注意,可以使用BST或散列表来替换排序,但通常它不会降低复杂性,因为您必须在2嵌套循环中插入/查询(O(lgN))。

答案 2 :(得分:0)

这是geeksforgeeks解决方案的修改版本,它也可以处理对和的重复项。我注意到有些对丢失了,因为当哈希表发现新的对满足总和时,哈希表将覆盖旧的对。因此,解决方法是通过将它们存储在成对的向量中来避免覆盖。希望这会有所帮助!

vector<vector<int> > fourSum(vector<int> &a, int t) {
    unordered_map<int, vector<pair<int,int> > > twoSum;
    set<vector<int> > ans;
    int n = a.size();
    for (int i = 0; i < n; i++) for (int j = i + 1; j < n; j++) twoSum[a[i] + a[j]].push_back(make_pair(i, j));
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            if (twoSum.find(t - a[i] - a[j]) != twoSum.end()) {
                for (auto comp : twoSum[t - a[i] - a[j]]) {
                    if (comp.first != i and comp.first != j and comp.second != i and comp.second != j) {
                        vector<int> row = {a[i], a[j], a[comp.first], a[comp.second]};
                        sort(row.begin(), row.end());
                        ans.insert(row);
                    }
                }
            }
        }
    }
    vector<vector<int> > ret(ans.begin(), ans.end());
    return ret;    
}