[LeetCode] 4Sum hash表


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)

 

Hide Tags
  Array Hash Table Two Pointers

    題目是給一個數組,從中選取4個,輸入全部組合,其和為target。
    題目操作起來好麻煩,調試了挺久,比較麻煩的是會有重復,時間上面需要考慮。
    最直接的是
  1. 排序
  2. 4層遍歷

  這個時間是O(n^4),這時間不用看也知道超時了。提升的想法是確定3個之后,使用二分法查找提升速度。

  1. 排序
  2. 3層遍歷
  3. 二分法查找剩下的target - a-b-c
 1 class Solution {
 2 public:
 3     vector<vector<int> > fourSum(vector<int> &num, int target) {
 4         sort(num.begin(),num.end());
 5         vector<vector<int> > ret;
 6         for(int a=0;a<num.size();){
 7             for(int b=a+1;b<num.size();){
 8                 for(int c=b+1;c<num.size();){
 9                     if(binary_search(num.begin()+c+1,num.end(),target-num[a]-num[b]-num[c]))
10                         ret.push_back({num[a],num[b],num[c],target-num[a]-num[b]-num[c]});
11                     c++;
12                     while(c<num.size()&&num[c-1]==num[c])    c++;
13                 }
14                 b++;
15                 while(b<num.size()&&num[b-1]==num[b])    b++;
16             }
17             a++;
18             while(a<num.size()&&num[a-1]==num[a])    a++;
19         }
20         return ret;
21     }
22 };
View Code

  這個時間是O(n^3 logn),我寫了這個,超時了,那么還需要提升時間,假如有兩個數確定了,問題變為從數組中找兩數,之和為定值,如果這個查找在有序數列上設左右指針,那么查找時間只需要O(n),這樣時間便為 O(n^3)

  1. 排序
  2. 從左遍歷,每次遍歷進入3
  3. 從右遍歷,每次進入4
  4. 設定左右索引,指向 2、3 還沒遍歷的數組框左右,判斷索引數之和與temp_target,大了右索引左移,小了左索引右移,符合的數放入return。

     這個沒有寫,如果還需要提高時間,那么這樣想,因為是4個數之和,可以看成兩組數之和,每組兩個數,這樣如果知道了每兩個數之和,問題如上面的轉換,這樣時間便是O(n^2),不過空間就需要大很多。維持如下的結構:

 

-2 -1 0 1 2
-2,0 -1,0 0,0 0,1 0,2
-1,-1 -2,1 -2,2 2,-1  
    -1,1    
         

  維持這樣的結構,第一行為組的和,然后指向所有的組合,因為c++ map 是會自動排序的,所以創建 map<int,pari<int,int> > > 這樣的一個表便可以了,然后就是剩下判斷問題了,如只有 -2 0 2 各一個,但是 -2 2  是可以的,所以需要考慮個數問題。

    我用了unorder_map,並沒有通過雙向收縮來實現,所以判斷起來比較麻煩,不過map 在初始化的時候,時間需要logn,所以這樣的總體時間是O(n^2logn),這個也是discuss 普遍時間。而使用unorder_map,我的時間是O(n^2 + n*Maxlen(bucket)^2),上圖就是Maxlen(bucket)=3,在n較大是較優,注意是+號,畢竟比較難表達,應該會接近O(n^2)。

  1. 計算兩數之和,放入mp 中
  2. 統計各數的個數,使用map<int,int> cnt 存儲
  3. 遍歷mp
    1. 判斷 target- val1 是否在mp 中,否繼續遍歷,這個時間是O(1)
    2. 存在的話,如果val1 > val2,continue,為了避免重復
    3. 遍歷bucket1 中的組合
      1. 遍歷bucket2 中的組合,如果 max(group1)<=min(group2)則進入下一步,這是為了避免重復,等號為了 0,0,0,0情況
      2. 通過cnt 判斷數的個數夠不夠,夠的放入return。
  4. 結束

  最終代碼如下:

  1 #include <iostream>
  2 #include <vector>
  3 #include <algorithm>
  4 #include <iterator>
  5 #include <unordered_map>
  6 using namespace std;
  7 /**
  8 class Solution {
  9 public:
 10     vector<vector<int> > fourSum(vector<int> &num, int target) {
 11         sort(num.begin(),num.end());
 12         vector<vector<int> > ret;
 13         for(int a=0;a<num.size();){
 14             for(int b=a+1;b<num.size();){
 15                 for(int c=b+1;c<num.size();){
 16                     if(binary_search(num.begin()+c+1,num.end(),target-num[a]-num[b]-num[c]))
 17                         ret.push_back({num[a],num[b],num[c],target-num[a]-num[b]-num[c]});
 18                     c++;
 19                     while(c<num.size()&&num[c-1]==num[c])    c++;
 20                 }
 21                 b++;
 22                 while(b<num.size()&&num[b-1]==num[b])    b++;
 23             }
 24             a++;
 25             while(a<num.size()&&num[a-1]==num[a])    a++;
 26         }
 27         return ret;
 28     }
 29 };
 30 */
 31 class Solution {
 32 public:
 33     vector<vector<int> > fourSum(vector<int> &num, int target) {
 34         sort(num.begin(),num.end());
 35         vector<vector<int> > ret;
 36         unordered_map<int,vector<pair<int,int> > > mp;
 37         unordered_map<int,int> cnt;
 38         for(unsigned int a=0;a<num.size();){
 39             for(unsigned int b=a+1;b<num.size();){
 40                 mp[num[a]+num[b]].push_back(pair<int,int> {num[a],num[b]});
 41                 b++;
 42                 while(b<num.size()&&num[b-1]==num[b])    b++;
 43             }
 44             a++;
 45             while(a<num.size()&&num[a-1]==num[a])    a++;
 46         }
 47         for(unsigned int a = 0;a<num.size();a++)
 48             cnt[num[a]]++;
 49 //        for(unordered_map<int,int>::iterator it=cnt.begin();it!=cnt.end();it++)
 50 //            cout<<it->first<<":"<<it->second<<endl;
 51 //        for(unordered_map<int,vector<pair<int,int> > >::iterator it1=mp.begin();it1!=mp.end();it1++){
 52 //            cout<<it1->first<<":"<<endl;
 53 //            for(int i=0;i<it1->second.size();i++)
 54 //                cout<<it1->second[i].first<<" "<<it1->second[i].second<<endl;
 55 //        }
 56 
 57         for(unordered_map<int,vector<pair<int,int> > >::iterator it1=mp.begin();it1!=mp.end();it1++){
 58 //            cout<<it1->first<<endl;
 59             unordered_map<int,vector<pair<int,int> > >::iterator it2=mp.find(target - it1->first);
 60             if(it2!=mp.end()){
 61 //                cout<<it1->first<<it2->first<<endl;
 62 //                cout<<it1->second.size()<<it2->second.size()<<endl;
 63                 if(it1->first > it2->first) continue;
 64                 for(int i=0;i<it1->second.size();i++){
 65                     for(int j=0;j<it2->second.size();j++){
 66                         int a = it1->second[i].first,b = it1->second[i].second,c = it2->second[j].first,d = it2->second[j].second;
 67                         if(max(a,b)<=min(c,d)){
 68                             bool flag = true;
 69                             cnt[a]--;
 70                             cnt[b]--;
 71                             cnt[c]--;
 72                             cnt[d]--;
 73                             if(cnt[a]<0||cnt[b]<0||cnt[c]<0||cnt[d]<0)  flag = false;
 74                             cnt[a]++;
 75                             cnt[b]++;
 76                             cnt[c]++;
 77                             cnt[d]++;
 78 //                            cout<<a<<" "<<b<<" "<<c<<" "<<d<<" "<<flag<<endl;
 79                             if(flag){
 80                                 vector<int> tmp = {a,b,c,d};
 81                                 sort(tmp.begin(),tmp.end());
 82                                 ret.push_back(tmp);
 83                             }
 84                         }
 85                     }
 86                 }
 87             }
 88         }
 89         return ret;
 90     }
 91 };
 92 
 93 
 94 
 95 
 96 int main()
 97 {
 98     vector<int > num = {1,0,-1,0,-2,2};
 99     Solution sol;
100     vector<vector<int> > ret = sol.fourSum(num,0);
101     for(unsigned  int i=0;i<ret.size();i++){
102         copy(ret[i].begin(),ret[i].end(),ostream_iterator<int>(cout," "));
103         cout<<endl;
104     }
105     return 0;
106 }
View Code

 

     需要注意的是mp 中的group 是不能重復的,就是如果有 <-1,0>那么便不會有<0,-1>。

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM