[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 };

  这个时间是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 }

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

时间: 2025-01-13 20:05:00

[LeetCode] 4Sum hash表的相关文章

python 字典有序无序及查找效率,hash表

刚学python的时候认为字典是无序,通过多次插入,如di = {}, 多次di['testkey']='testvalue' 这样测试来证明无序的.后来接触到了字典查找效率这个东西,查了一下,原来字典在python内部是通过哈希表的顺序来排的,做了一些测试,比如di = {1:1,3:3,2:2,4:4,5:5} ,无论怎么改变键值对的顺序,print di 总是会{1: 1, 2: 2, 3: 3, 4: 4, 5: 5}.所以看起来当插入di['key']='value'时,这组键值对有时

[leetcode]4Sum @ Python

原题地址:http://oj.leetcode.com/problems/4sum/ 题意:从数组中找到4个数,使它们的和为target.要求去重,可能有多组解,需要都找出来. 解题思路:一开始想要像3Sum那样去解题,时间复杂度为O(N^3),可无论怎么写都是Time Limited Exceeded.而同样的算法使用C++是可以通过的.说明Python的执行速度比C++慢很多.还说明了一点,大概出题人的意思不是要让我们去像3Sum那样去解题,否则这道题就出的没有意义了.这里参考了kitt的解

【leetcode 哈希表】Majority Element

[leetcode 哈希表]Majority Element @author:wepon @blog:http://blog.csdn.net/u012162613 1.题目 Given an array of size n, find the majority element. The majority element is the element that appears more than ? n/2 ? times. You may assume that the array is no

[Leetcode] 4Sum

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.

Hash表的表大小

hash表的出现主要是为了对内存中数据的快速.随机的访问.它主要有三个关键点:Hash表的大小.Hash函数.冲突的解决. 这里首先谈谈第一点:Hash表的大小. Hash表的大小一般是定长的,如果太大,则浪费空间,如果太小,冲突发生的概率变大,体现不出效率.所以,选择合适的Hash表的大小是Hash表性能的关键. 对于Hash表大小的选择通常会考虑两点: 第一,确保Hash表的大小是一个素数.常识告诉我们,当除以一个素数时,会产生最分散的余数,可能最糟糕的除法是除以2的倍数,因为这只会屏蔽被除

南阳OJ-138 找球号(二)(hash表应用)

找球号(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描述 在某一国度里流行着一种游戏.游戏规则为:现有一堆球中,每个球上都有一个整数编号i(0<=i<=100000000),编号可重复,还有一个空箱子,现在有两种动作:一种是"ADD",表示向空箱子里放m(0<m<=100)个球,另一种是"QUERY",表示说出M(0<M<=100)个随机整数ki(0<=ki<=100000100),分

hash表总结

Hash表也称散列表,也有直接译作哈希表,Hash表是一种特殊的数据结构,它同数组.链表以及二叉排序树等相比较有很明显的区别,它能够快速定位到想要查找的记录,而不是与表中存在的记录的关键字进行比较来进行查找.这个源于Hash表设计的特殊性,它采用了函数映射的思想将记录的存储位置与记录的关键字关联起来,从而能够很快速地进行查找. 1.Hash表的设计思想 对于一般的线性表,比如链表,如果要存储联系人信息: 张三 13980593357 李四 15828662334 王五 13409821234 张

hdu 5183 hash表

BC # 32 1002 题意:给出一个数组 a 和一个数 K ,问是否存在数对( i , j ),使 a i   - a i + 1 +……+ (-1)j - i  a j : 对于这道题,一开始就想到了是前缀和,但是如果只是记录下前缀和数组,那么查找就会成为一个大问题.补题的时候一开始考虑用 hash 数组或者是 set 存,但是很明显 TLE 了,在翔神的推荐下,我研究了一下 hash表的创建过程,惊奇地发现,其实就是建了一个 HashMap 结构体,而里面放了这个表所用的数组以及相应操作

nyist oj 138 找球号(二)(hash 表+位运算)

找球号(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描述 在某一国度里流行着一种游戏.游戏规则为:现有一堆球中,每个球上都有一个整数编号i(0<=i<=100000000),编号可重复,还有一个空箱子,现在有两种动作:一种是"ADD",表示向空箱子里放m(0<m<=100)个球,另一种是"QUERY",表示说出M(0<M<=100)个随机整数ki(0<=ki<=100000100),分