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
 class Solution {
public:
vector<vector<int> > fourSum(vector<int> &num, int target) {
sort(num.begin(),num.end());
vector<vector<int> > ret;
for(int a=;a<num.size();){
for(int b=a+;b<num.size();){
for(int c=b+;c<num.size();){
if(binary_search(num.begin()+c+,num.end(),target-num[a]-num[b]-num[c]))
ret.push_back({num[a],num[b],num[c],target-num[a]-num[b]-num[c]});
c++;
while(c<num.size()&&num[c-]==num[c]) c++;
}
b++;
while(b<num.size()&&num[b-]==num[b]) b++;
}
a++;
while(a<num.size()&&num[a-]==num[a]) a++;
}
return ret;
}
};

  这个时间是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. 结束

  最终代码如下:

 #include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <unordered_map>
using namespace std;
/**
class Solution {
public:
vector<vector<int> > fourSum(vector<int> &num, int target) {
sort(num.begin(),num.end());
vector<vector<int> > ret;
for(int a=0;a<num.size();){
for(int b=a+1;b<num.size();){
for(int c=b+1;c<num.size();){
if(binary_search(num.begin()+c+1,num.end(),target-num[a]-num[b]-num[c]))
ret.push_back({num[a],num[b],num[c],target-num[a]-num[b]-num[c]});
c++;
while(c<num.size()&&num[c-1]==num[c]) c++;
}
b++;
while(b<num.size()&&num[b-1]==num[b]) b++;
}
a++;
while(a<num.size()&&num[a-1]==num[a]) a++;
}
return ret;
}
};
*/
class Solution {
public:
vector<vector<int> > fourSum(vector<int> &num, int target) {
sort(num.begin(),num.end());
vector<vector<int> > ret;
unordered_map<int,vector<pair<int,int> > > mp;
unordered_map<int,int> cnt;
for(unsigned int a=;a<num.size();){
for(unsigned int b=a+;b<num.size();){
mp[num[a]+num[b]].push_back(pair<int,int> {num[a],num[b]});
b++;
while(b<num.size()&&num[b-]==num[b]) b++;
}
a++;
while(a<num.size()&&num[a-]==num[a]) a++;
}
for(unsigned int a = ;a<num.size();a++)
cnt[num[a]]++;
// for(unordered_map<int,int>::iterator it=cnt.begin();it!=cnt.end();it++)
// cout<<it->first<<":"<<it->second<<endl;
// for(unordered_map<int,vector<pair<int,int> > >::iterator it1=mp.begin();it1!=mp.end();it1++){
// cout<<it1->first<<":"<<endl;
// for(int i=0;i<it1->second.size();i++)
// cout<<it1->second[i].first<<" "<<it1->second[i].second<<endl;
// } for(unordered_map<int,vector<pair<int,int> > >::iterator it1=mp.begin();it1!=mp.end();it1++){
// cout<<it1->first<<endl;
unordered_map<int,vector<pair<int,int> > >::iterator it2=mp.find(target - it1->first);
if(it2!=mp.end()){
// cout<<it1->first<<it2->first<<endl;
// cout<<it1->second.size()<<it2->second.size()<<endl;
if(it1->first > it2->first) continue;
for(int i=;i<it1->second.size();i++){
for(int j=;j<it2->second.size();j++){
int a = it1->second[i].first,b = it1->second[i].second,c = it2->second[j].first,d = it2->second[j].second;
if(max(a,b)<=min(c,d)){
bool flag = true;
cnt[a]--;
cnt[b]--;
cnt[c]--;
cnt[d]--;
if(cnt[a]<||cnt[b]<||cnt[c]<||cnt[d]<) flag = false;
cnt[a]++;
cnt[b]++;
cnt[c]++;
cnt[d]++;
// cout<<a<<" "<<b<<" "<<c<<" "<<d<<" "<<flag<<endl;
if(flag){
vector<int> tmp = {a,b,c,d};
sort(tmp.begin(),tmp.end());
ret.push_back(tmp);
}
}
}
}
}
}
return ret;
}
}; int main()
{
vector<int > num = {,,-,,-,};
Solution sol;
vector<vector<int> > ret = sol.fourSum(num,);
for(unsigned int i=;i<ret.size();i++){
copy(ret[i].begin(),ret[i].end(),ostream_iterator<int>(cout," "));
cout<<endl;
}
return ;
}

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

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

  1. LeetCode Continuous Subarray Sum 题解 同余前缀和 Hash表

    文章目录 题意 思路 特殊情况k=0 Source Code 1 Source Code 2 题意 给定一个数组和一个整数k,返回是否存在一个长度至少为2的连续子数组的和为k的倍数. 思路 和上一篇博 ...

  2. 【数据结构】Hash表简介及leetcode两数之和python实现

    文章目录 Hash表简介 基本思想 建立步骤 问题 Hash表实现 Hash函数构造 冲突处理方法 leetcode两数之和python实现 题目描述 基于Hash思想的实现 Hash表简介 基本思想 ...

  3. leetcode的Hot100系列--347. 前 K 个高频元素--hash表+直接选择排序

    这个看着应该是使用堆排序,但我图了一个简单,所以就简单hash表加选择排序来做了. 使用结构体: typedef struct node { struct node *pNext; int value ...

  4. LeetCode longest substring without repeating characters 题解 Hash表

    题目 Given a string, find the length of the longest substring without repeating characters. Example 1: ...

  5. LeetCode subarray-sum-equals-k题解 前缀和+Hash表+枚举——线性做法

    文章目录 题意 思路 连续子数组的和sum[i,j] 源码 结果记录 题意 给定一个数组,求连续的子数组的和为k的子数组个数. 思路 连续子数组的和sum[i,j] sum[i,j]=∑k=ijAk( ...

  6. LeetCode哈希表

    1. Two Sum https://leetcode.com/problems/two-sum/description/ 不使用额外空间需要n*n的复杂度 class Solution { publ ...

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

    刚学python的时候认为字典是无序,通过多次插入,如di = {}, 多次di['testkey']='testvalue' 这样测试来证明无序的.后来接触到了字典查找效率这个东西,查了一下,原来字 ...

  8. 四种方式带你层层递进解剖算法---hash表不一定适合寻找重复数据

    一.题目描述 找出数组中重复的数字 > 在一个长度为 n 的数组 nums 里的所有数字都在 0-n-1 的范围内.数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次. ...

  9. hash表长度优化证明

    hash表冲突的解决方法一般有两个方向: 一个是倾向于空间换时间,使用向量加链表可以最大程度的在节省空间的前提下解决冲突. 另外一个倾向于时间换空间,下面是关于这种思路的一种合适表长度的证明过程: 这 ...

随机推荐

  1. Shell脚本使用汇总整理——文件夹及子文件备份脚本

    Shell脚本使用汇总整理——文件夹及子文件备份脚本 Shell脚本使用的基本知识点汇总详情见连接: https://www.cnblogs.com/lsy-blogs/p/9223477.html ...

  2. 利用DOM的方式点击切换图片及修改文字

    本案例主要学习理解,用到的几个DOM方法 01.getAttribute()方法,获取元素的属性值 02.setAttribute('src',source) 方法,用后边的值修改前边这个元素的属性值 ...

  3. iOS SDK中使用NSXMLParser解析XML(iphone网络篇三)

    iOS SDK的NSXMLParser解析XML文档是事件驱动模式的,即采用SAX方式来解析XML格式文档.NSXMLParser在处理XML文档的过程中当遇到一些要素(元素.属性.CDATA块.评论 ...

  4. 动态规划:HDU2159-FATE(二维费用的背包问题)

    FATE Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  5. KMP的正确使用法_x新疆网络赛Query on a string

    Query on a string 题意,给定一个大字符串,给定一个小模式串,定义 两种不同的任务模式,分别是查询和更改: 查询对应区间内,有多少个匹配到位的数字: 修改某一位的某一个字母. 于是直觉 ...

  6. Linux命令之---which简单介绍

    命令简介 which命令的作用是,在PATH变量指定的路径中,搜索某个系统命令的位置,并且返回第一个搜索结果.也就是说,使用which命令,就可以看到某个系统命令是否存在,以及执行的到底是哪一个位置的 ...

  7. 笔记-python-内存管理

    笔记-python-内存管理 1.      内存使用 1.1.    对象的内存使用 a = 1 1是一个对象,a是引用,指向1. >>> id(a) 1951821280 这个数 ...

  8. eeeeeeeeeee

    http://58.241.123.38/hot.cdn.baidupcs.com/file/91623e76f776475da9c3223cdac861f0?xcode=68983c005f6e3c ...

  9. Mdrill集群安装

    Mdrill集群安装 mdrill是阿里妈妈-adhoc-海量数据多维自助即席查询平台下的一个子项目.旨在帮助用户在几秒到几十秒的时间内,分析百亿级别的任意维度组合的数据.mdrill是一个分布式的在 ...

  10. OpenCV学习笔记(四) Mat的简单操作

    转自:OpenCV Tutorial: core 模块. 核心功能 改变图像对比度和亮度:convertTo 可以把  看成源图像像素,把  看成输出图像像素.这样一来,调整亮度和对比度的方法可表示为 ...