zoukankan      html  css  js  c++  java
  • [LeetCode] 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)

    这题各种面熟,先来暴力的吧。因为要求abcd是递增的,所以可以先将num排序以后再爆,嗯。

    我擦咧闹不住暴破法(Time Limit Exceed):

     1     vector<vector<int> > fourSum(vector<int> &num, int target) {
     2             vector<vector<int>>result;
     3             if (num.size() < 4) return result;
     4             sort(num.begin(), num.end());
     5             for (int i=0; i<num.size()-3; i++){
     6                 for (int j=i+1; j<num.size()-2; j++){
     7                     for (int k=j+1; k<num.size()-1; k++){
     8                         for (int v=k+1; v<num.size(); v++){
     9                             if (num[i]+num[j]+num[k]+num[v] == target){
    10                                 vector<int>tmp;
    11                                 tmp.push_back(num[i]);
    12                                 tmp.push_back(num[j]);
    13                                 tmp.push_back(num[k]);
    14                                 tmp.push_back(num[v]);
    15                                 result.push_back(tmp);
    16                             }
    17                         }
    18                     }
    19                 }
    20             }
    21             return result;
    22     }

    O(n^4)就是个娱乐,别说大集合没戏,连稍微大一点的集合都过不了的。

    看看优化,可以把最后一层循环n变成logn, 思想是最后一层循环实际上是为了从 [k+1, num.size()) 中找到一个数x且x=target - (num[i]+num[j]+num[k]) 。这样我们就可以用二分查找代替遍历,所以原本的O(n^4)就变成了O(n^3 logn)
    复杂度依然是难以接受的,但至少比n^4要好一丢丢,期待进一步优化...

    我擦咧稍微闹得住一丢丢暴破法(Time Limit Exceed):

     1     vector<vector<int> > fourSum(vector<int> &num, int target) {
     2             vector<vector<int>>result;
     3             if (num.size() < 4) return result;
     4             sort(num.begin(), num.end());
     5             for (int i=0; i<num.size()-3; i++){
     6                 for (int j=i+1; j<num.size()-2; j++){
     7                     for (int k=j+1; k<num.size()-1; k++){
     8                         if (binary_search(num.begin()+k+1, num.end(), target - num[i]-num[j]-num[k])){
     9                             vector<int>tmp;
    10                             tmp.push_back(num[i]);
    11                             tmp.push_back(num[j]);
    12                             tmp.push_back(num[k]);
    13                             tmp.push_back(target - num[i]-num[j]-num[k]);
    14                             result.push_back(tmp);
    15                         }
    16                     }
    17                 }
    18             }
    19             return result;
    20     }

    通过一些挣扎看了一些答案,虽然还是n^3但是500ms可以通过大集合。

     1     vector<vector<int> > fourSum(vector<int> &num, int target) {
     2             vector<vector<int>>result;
     3             if (num.size() < 4) return result;
     4             sort(num.begin(), num.end());
     5             for (int i=0; i<num.size()-3; i++){
     6                 if (i && num[i] == num[i-1]) continue;
     7                 for (int j=i+1; j<num.size()-2; j++){
     8                     if (j>i+1&&num[j]==num[j-1])continue;
     9                     for (int k=j+1; k<num.size()-1; k++){
    10                         if (k>j+1&& num[k]==num[k-1])continue;
    11                         int tarV = target-(num[i]+num[j]+num[k]);
    12                         if (num[k+1] > tarV || num[num.size()-1] < tarV)continue;
    13                         if (binary_search(num.begin()+k+1, num.end(), target - num[i]-num[j]-num[k])){
    14                             vector<int>tmp;
    15                             tmp.push_back(num[i]);
    16                             tmp.push_back(num[j]);
    17                             tmp.push_back(num[k]);
    18                             tmp.push_back(target - num[i]-num[j]-num[k]);
    19                             result.push_back(tmp);
    20                         }
    21                     }
    22                 }
    23             }
    24             return result;
    25     }

    有几点需要优化,一是每层遍历的时候注意过滤掉重复的选择(这一轮跟上一轮选了一样的数)。 还有第12行的过滤也很重要,判断最后一个数的第一个可能是否大于我们想要的结果,大于的话说明之后的每个数都要比它大,因为num已经被排序了。
    同理,还要判断num的最后一个数是否小于tar,如果小于的话也没必要再二分找了,根本不存在。

    这题还有更为优化的n^2法,貌似使用hash, 把内层的两两之和遍历出来以后,同索引放在hash map 里。思路大概是这样,等我之后验证。

  • 相关阅读:
    为什么java使用对象序列化到文件,打开之后是乱码,而且更换编码格式查看也不能正常显示呢
    String类能够导入IDEA,但是里面的构造方法无法使用,一直显示报错
    IDEA不能提示导入java.io.File类,但是自己手写import没问题,最后找到了问题所在
    扑克牌发牌,排序的功能实现
    TFS 生成定义
    Git-tfs工具
    日期和时间
    调用惯例
    优化查找和排序
    使用更好的库
  • 原文地址:https://www.cnblogs.com/agentgamer/p/3696854.html
Copyright © 2011-2022 走看看