• 【Leetcode】【Medium】4Sum


    Given an array S of n integers, are there elements abc, 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)

    在Leetcode中,除了4Sum以外,还有3Sum以及2Sum,有兴趣的朋友可以点击链接参考。

    一、解题思路1:

    在3Sum以及2Sum的基础上,可以总结出KSum的通用算法,那就是数组中按序挑选数字作为target(o(n)),对于余下的序列使用(K-1)Sum算法,其中2Sum的复杂度是o(n);

    二、针对4Sum的解题思路2:

    1、4Sum可以分解为2Sum+2Sum;因此将原始数组中,所有数字两两求和,记录在hash表;那么原来的4Sum=target的问题,就转为从hash表中找到2个Item使其Sum之和为target的问题;满足一个值的item可能有多种组合存在(如题目中的例子item=0,那么(-1,1)(-2,2)(0,0)都应保存在此item下),因此hash表可以将键值作为item值,而将value设为一个list,保存所有满足的组合。

    2、如何操作hash表:

      我们可以倒过来思考,假设A+B+C+D=target,ABCD各不相同;由于hash表保存了所有元素两两之和的结果,即AB、AC、AD、BC、BD、CD都单独存在表中,如果仅仅寻找和为target的item组合的话,一共有AB+CD、AC+BD、AD+BC、BC+AD、BD+AC、CD+AB 6种情况满足和为target,但是他们都只对应一种返回值(A、B、C、D);

      为了避免出现6次重复结果,由于一个item中(例AC、BD)两个元素的排列顺序也是按照从小到大有序排列,因此我们只针对AB+CD的情况筛选。即如果两个item的和等与target,同时要满足item1的第二个值B要小于item2的第一个元素C,那么可以当做结果录入返回队列中,否则当做不符合要求。

    3、除了以上措施避免重复之外,由于数组队列中存在重复的元素,并且第一轮建立hash表时不会对重复元素筛选剔除。因此要注意不要将某一值计算两次;

    时间复杂度:

    第一部分建立hash表需要n(n-1)/2,假设两两和值有x个,每个值平均有k种组合,那么x*k = n(n-1)/2;

    所以程序时间复杂度为 o( n(n-1)/2 + x*k*k ) = o( n(n-1)/2 * (1+k) ),即时间复杂度约为o(kn2) ,k取值: 1~n(n-1)/2;

    最好的情况是两两和值没有重复,x=n(n-1)/2,k=1;那么程序时间复杂度为o(n2);

    最坏的情况是数组中所有元素都相等,那么x=1,k=n(n-1)/2,时间复杂度接近o(n4);

    AC代码:

     1 class Solution {
     2 public:
     3     vector<vector<int> > fourSum(vector<int> &num, int target) {
     4         vector<vector<int> > ret;
     5         unordered_map<int, vector<pair<int, int> > > hmap;
     6         sort(num.begin(), num.end());
     7         int size = num.size();
     8         
     9         for (int i = 0; i < size - 1; ++i) {
    10             for (int j = i + 1; j < size; ++j) {
    11                 hmap[num[i]+num[j]].push_back(make_pair(i, j));
    12             }
    13         }
    14         
    15         unordered_map<int, vector<pair<int, int> > >::iterator itr;
    16         for (itr = hmap.begin(); itr != hmap.end(); ++itr) {
    17             int new_target = target - itr->first;
    18             if (hmap.find(new_target) == hmap.end())
    19                 continue;
    20             vector<pair<int, int> > group1 = itr->second;
    21             vector<pair<int, int> > group2 = hmap[new_target];
    22             
    23             for (int i = group1.size() - 1; i >= 0; --i) {
    24                 if (i == group1.size() - 1 || num[group1[i].first] != num[group1[i+1].first]) {
    25                     for (int j = 0; j < group2.size(); ++j) {
    26                         if (group2[j].second < group1[i].first && 
    27                             (j == 0 || num[group2[j].first] != num[group2[j-1].first])) {
    28                             vector<int> one_res {num[group2[j].first], 
    29                                                 num[group2[j].second], 
    30                                                 num[group1[i].first], 
    31                                                 num[group1[i].second]};
    32                             ret.push_back(one_res);
    33                         }
    34                     }
    35                 }
    36             }
    37         }
    38         
    39         return ret;
    40     }
    41 };

    附录:

    C++ Hash表操作;

    
    
  • 相关阅读:
    2.6
    zuoye
    练习1
    练习
    练习
    4
    3
    2
    1
    1.3
  • 原文地址:https://www.cnblogs.com/huxiao-tee/p/4232570.html
Copyright © 2020-2023  润新知