AcWing 840. 模拟散列表
题目描述
餐前小菜:
在讨论本题目之前先看一个简单的问题:给出 NNN 个正整数 (a1,a2,...,an)(a_1,a_2,...,a_n)(a1,a2,...,an),再给出 MMM 个正整数 (x1,x2,...,xm)(x_1,x_2,...,x_m)(x1,x2,...,xm),问这 MMM 个数中的每个数是否在 NNN 个数中出现过,其中 N,M≤105N,M ≤ 10^5N,M≤105,且所有正整数均不超过 10510^5105。比较容易想到的思路是:对每个欲查询的数 xix_ixi,遍历 NNN 看看是否存在。该算法时间复杂度为 O(NM)O(NM)O(NM),是有很多的优化空间的。
经典思想为用空间换时间,设有一个 hashTable[N],其中 hashTable[xix_ixi] == true 表示正整数 xix_ixi 在 NNN 个正整数 (a1,a2,...,an)(a_1,a_2,...,a_n)(a1,a2,...,an) 中找到了与之相等的数,若为 false 表示没有出现过。我们该怎么做呢?初始时 hashTable 全为 false,对读入的 NNN 个数 (a1,a2,...,an)(a_1,a_2,...,a_n)(a1,a2,...,an),进行预处理将 hashTable[aia_iai] 设置为 true,接着对 MMM 个欲查正整数,直接查看 hashTable[xix_ixi] 为 true/false 来判断出现/没出现过。在许多算法里都用到了这样一种方案:把输入的数作为数组下标来进行查询。将查询的时间复杂度降低至 O(1)O(1)O(1)。
分析:
但注意本题中,我们每个数的范围是 [−109,109][-10^9,10^9][−109,109] 这是没有办法作为数组下标进行查询的!因此我们希望能将一些不合适的下标(负数或过大)转换为我们期望的一个范围内。
因此我们引入哈希(散列、hash)的思想,将元素(element, e)通过一个函数转换为整数,使得该整数可以尽量地代表这个元素。该函数称为哈希函数 h()h()h()。即对 eee,求 h(e)h(e)h(e)。
看看这道题 −109≤e≤109-10^9≤e≤10^9−109≤e≤109 为整数,可以使用哪些常用的哈希函数呢?
- 直接定址法(简单,常用于映射要求不高的题目): h(e)=eh(e)=eh(e)=e。餐前小菜中对于需要查找的 xix_ixi,其实就是使用了该方案,有一个隐式的h(xi)=xih(x_i)=x_ih(xi)=xi,将要查询的数作为数组下标。
- 平方取中法(基本不使用该方法,可忽略):将 eee 的平方的中间若干位作为 hash 值。
- 除留余数法(重要,常用):h(e)=eh(e)=eh(e)=e modmodmod kkk。通过该哈希函数,可以把很大的数转换为一个不超过 kkk 的数,这样就可以作为可行的数组下标。这里 TableSize(即可 hash 映射的总长度必须大于等于 kkk,不然会产生越界),当 kkk 是一个素数时,h(e)h(e)h(e) 能尽可能覆盖 [0,k)[0,k)[0,k) 范围内的每一个数。这里将 TableSize与 kkk 都设置为相同的素数。但本题远没有这么简单,有两点需要注意:
① e 的取值可能为负,在人类世界里负数的模有各种各样的计算方法,但总归会得到一个在现有规则下“正确的”一个非负数解,同理根据高级程序语言的不同计算的方式也不同,但结果却不尽相同,在C/C++中,若对负数求模运算,会得到一个负的解,这显然是与模运算的定义所违背的,因此需要对运算结果进行加工:ans = (e % TableSize + TableSize) % TableSize
,这样不论是正数还是负数都能得到正确的解,具体的细节不多做解释,可以将它看作是与加减乘除相类似的算法。
② TableSize 该如何选取呢?这是很重要的一点,同时也决定了哈希函数(与 k 有关)的设计。按照上文分析, TableSize 又应该大于等于输入总数 NNN 的质数且根据上文需要大于等于 kkk,而 k 应为一个质数,我们得到一下关系:TableSize=k≥NTableSize=k≥NTableSize=k≥N,而 NNN 不是质数,因此不使用它,我们可以使用比 NNN 大的第一个质数。// 求比 N 大的第一个质数 N = 100000 for (int i = N; ; i ++) {bool flag = false;for (int j = 2; j * j <= i; j ++){if (i % j == 0){flag = true;break;}}if (flag){cout << i << endl;break;} }>_: 100003
以我们对求余运算的了解,对于两不同的数 e1,e2e_1,e_2e1,e2,他们的 hash值可能是相同的,当 e1e_1e1 将表中下标为 h(e1)h(e_1)h(e1) 的单元占据时,e2e_2e2 便不能再使用这个位置了,此时发生了冲突。
为解决冲突,将介绍一下三种方法,其中第一、二种都计算了新的 hash 值,又称为开放寻址法:
- 线性探测法(Linear Probing):当得到 eee 的 hash值h(e)hash值 h(e)hash值h(e) 后,观察到 hashTable 中下标为 h(e)h(e)h(e) 的位置已经被其他元素占用,那么就检查下个位置 h(e)+1h(e)+1h(e)+1 是否被占用,如果没有,就使用这个位置;如果还是被占用就继续向后检查,当检查长度超出 TableSize 时,就回到表头继续向后查找,知道找到能使用的位置或表中所有位置均被使用过为止。这种做法容易扎堆。同时,由于线性探测法有向后检查的特征,因此 hashTable 的设置至少要为 N 的 2 倍,又根据我们在除留余数法中的分析,TableSize 为 200003。而具体实现中,用一个极大值(0x3f3f3f3f)(0x3f3f3f3f)(0x3f3f3f3f)来标识一个位置是否被占用,如被占用,则 hashTable[h(e)]=ehashTable[h(e)] =ehashTable[h(e)]=e,否则 hashTable[h(e)]=0x3f3f3f3fhashTable[h(e)]=0x3f3f3f3fhashTable[h(e)]=0x3f3f3f3f。
- 平方探测法(Quadratic probing):在平方探测法中,为了尽可能避免扎堆现象,当表中 h(e)h(e)h(e) 的位置被占用时,将按下面的顺序检查表中的位置:h(e)+12、h(e)−12、h(e)+22、h(e)−22、h(e)+32...h(e)+1^2、h(e)-1^2、h(e)+2^2、h(e)-2^2、h(e)+3^2...h(e)+12、h(e)−12、h(e)+22、h(e)−22、h(e)+32...。①如果检查过程中 h(e)+i2>TableSizeh(e)+i^2>TableSizeh(e)+i2>TableSize 时(下个位置超出表尾),就把 h(e)+i2h(e)+i^2h(e)+i2 对 TableSize 取模;②如果检查过程中 h(e)−i2<0h(e)-i^2<0h(e)−i2<0时(下个位置超出表头),就将((h(e)−i2)modTableSize+TableSize)modTableSize((h(e)-i^2)modTableSize+TableSize)modTableSize((h(e)−i2)modTableSize+TableSize)modTableSize 作为结果,如果为避免出现负数的麻烦可以只进行正方向的平方探测。有结论证明,如果 eee 在 [0,TableSize][0,TableSize][0,TableSize] 范围内都无法找到位置,当 i≥TableSizei≥TableSizei≥TableSize 时,也一定无法找到位置。
- 链地址法(拉链法):拉链法不计算新的 hash值,而是把所有 h(e)h(e)h(e) 相同的 eee 连接成一条单链表。,若 e1,e2e_1,e_2e1,e2 有相同 hash值,则可以形成这样一个单链表:
可以看到,线性探测法比较直观而拉链法操作比较多,因此对其进行模拟一下,请结合代码理解!
代码(C++)
线性探测法
#include <iostream>using namespace std;// TS: TableSize
const int TS = 200003, null = 0x3f3f3f3f;
int hashtable[TS];// 哈希函数,输入元素返回哈希值用于初步定位 hashtable
// h(e) 返回的是未经线性探测的位置
int h(int e)
{return (e % TS + TS) % TS;
}// find(e) 返回经过线性探测的位置
int find(int e)
{int he = h(e);while (hashtable[he] != null && hashtable[he] != e){he ++;if (he == TS) he = 0;}return he;
}int main()
{int n;cin >> n;// 初始化时,每一位都没有被占用,即没有出现过for (int i = 0; i < TS; i ++) hashtable[i] = null;while (n --){char op;int e;cin >> op >> e;// 找到最终位置后进行插入if (op == 'I') hashtable[find(e)] = e;else{// 通过经过线性探测的位置来判断 e 的性质//而不能通过计算一次哈希函数就去hashtable看if (hashtable[find(e)] == null) cout << "No" << endl;else cout << "Yes" << endl;}}
}
拉链法
#include <iostream>using namespace std;const int TS = 100003;
// TS: TableSize, no: node, ne: next
int hashtable[TS], no[TS], ne[TS], idx;int h(int e)
{// 哈希函数,输入元素返回哈希值用于初步定位 hashtablereturn (e % TS + TS) % TS;
}void insert(int e)
{int he = h(e);no[idx] = e;ne[idx] = hashtable[he];hashtable[he] = idx ++;
}int find(int e)
{int he = h(e);// 通过 hashtable[he] 可以查询到最后一个被连接到 h(e) 位置的元素// 再顺着该元素往前查看,看 e 是否在此链中出现过for (int i = hashtable[he]; i != -1; i = ne[i]){// i 实际上为 idxif (no[i] == e) return true;}return false;
}int main()
{int n;cin >> n;// 每个位置的链没有连接元素for (int i = 0; i < TS; i ++) hashtable[i] = -1;while (n --){char op;int e;cin >> op >> e;if (op == 'I') insert(e);else{if (find(e)) cout << "Yes" << endl;else cout << "No" << endl;}}
}
相关文章:
AcWing 840. 模拟散列表
题目描述 餐前小菜: 在讨论本题目之前先看一个简单的问题:给出 NNN 个正整数 (a1,a2,...,an)(a_1,a_2,...,a_n)(a1,a2,...,an),再给出 MMM 个正整数 (x1,x2,...,xm)(x_1,x_2,...,x_m)(x1,x2,...,xm),问这 MMM 个数中…...
【网络工程】常见HTTP响应状态码
前言 什么是HTTP响应状态码? HTTP状态码(HTTP Status Code)是表示网页服务器超文本传输协议响应状态的3位数字代码 HTTP响应码被分为五大类 信息响应(100~199)成功响应(200~299)重定向响应&am…...
Python之ruamel.yaml模块详解(二)
Python之ruamel.yaml模块详解(二)4 将YAML解析为Python对象并修改5 使用旧API将YAML解析为Python对象并修改6 使用[]和.get()访问合并的键:7 使用insert()方法插入内容8 使用yaml.indent()更改默认缩进9 使用yaml.compact()隔行显示10 同一数…...
若依框架 --- 偶发的el-select无法选择的问题
👏作者简介:大家好,我是小童,Java开发工程师,CSDN博客博主,Java领域新星创作者 📕系列专栏:前端、Java、Java中间件大全、微信小程序、微信支付、若依框架、Spring全家桶 Ǵ…...
【Linux】tmpfile 使用介绍
tmpfile 使用介绍 1 介绍 很多情况下,需要系统自动识别/tmp、/var/tmp下的临时目录,并将其自动清理其中的过期文件。这个工具就是systemd-tmpfiles。 网上很多博客使用tmpwatchcron的方法来管理临时文件和临时存放文件的目录,在后期的版本…...
实现光线追踪重投影的方法
光线追踪重投影方法 重投影这项技术一般用于时间性帧复用技术上,例如TAA(Temporal Anti-Aliasing)反走样或者抗锯齿技术。读这篇文章最好先对TAA这类技术的算法流程有了解。 1.TAA抗锯齿技术简介 先简单介绍下TAA抗锯齿的原理,在游戏中,当前…...
Hyperbolic Representation Learning for CV
Contents Hyperbolic geometry[CVPR 2020] Hyperbolic visual embedding learning for zero-shot recognitionIntroductionApproachHyperbolic Label Embedding LearningHyperbolic Image Embedding LearningExperiment[CVPR 2020] Hyperbolic Image EmbeddingsIntroduction...
In Context Learning 相关分享
个人知乎详见 https://zhuanlan.zhihu.com/p/603650082/edit 1. 前言 随着大模型(GPT3,Instruction GPT,ChatGPT)的横空出世,如何更高效地提示大模型也成了学术界与工业界的关注,因此In-context learning…...
【前端笔试题一】:解析url路径中的query参数
前言 本文记录下在笔试过程中的前端笔试编程题目,会持续更新 1. 题目: 解析 url 路径中的 query 参数,比如:‘http://building/#/skeleton?serialNumber2023020818332821073&jobNo210347&target%7B%22a%22%3A%22b%22%2C…...
K_A12_001 基于STM32等单片机采集火光火焰传感参数串口与OLED0.96双显示
K_A12_001 基于STM32等单片机采集火光火焰传感参数串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RC火光火焰模块1.2、STM32F103C8T6火光火焰模块五、基础知识学习与相…...
Java基础42 枚举与注解
枚举与注解一、枚举(enumeration)1.1 自定义类实现枚举1.2 enum关键字实现枚举1.2.1 enum的注意事项1.2.2 enum的使用练习1.2.3 enum的常用方法1.2.4 enum的使用细节及注意事项1.2.5 enum练习二、注解(Annotation)2.1 Override&am…...
shell的变量和引用
文章目录二、变量和引用2.1 什么是变量2.2变量的命名2.3 变量的类型2.3.1 根据数据类型分类2.3.2 根据作用域分类2.4 变量的定义2.5 shell中的引用2.6 变量的运算练习:二、变量和引用 在程序设计语言中,变量是一个非常重要的概念。也是初学者在进行Shel…...
基于PHP的招聘网站
摘要在Internet高速发展的今天,我们生活的各个领域都涉及到计算机的应用,其中包括在线招聘的网络应用,在外国在线招聘已经是很普遍的方式,不过国内的在线招聘可能还处于起步阶段。招聘网站具有招聘信息功能的双向选择,…...
轻松使用 Python 检测和识别车牌(附代码)
车牌检测与识别技术用途广泛,可以用于道路系统、无票停车场、车辆门禁等。这项技术结合了计算机视觉和人工智能。 本文将使用Python创建一个车牌检测和识别程序。该程序对输入图像进行处理,检测和识别车牌,最后显示车牌字符,作为…...
DVWA—CSRF-Medium跨站请求伪造中级
注意: 1、这里对XSS(Stored)关卡不熟悉的可以从这里去看http://t.csdn.cn/ggQDK 2、把难度设置成 Medium 一、这一关同样我们需要埋下伏笔,诱使用户点击来提交,首先从XSS(Stored)入手。 注意:在前面介绍…...
【电商】后台订单生成
结合商品流转的电商系列介绍了一些了,商品已经采购入库、价格税率设置好了、活动及相关模板也已经准备完毕,下面就应该上架销售了,现在接着聊下订单的生成。 订单从产生到最终的关闭需要经历很多的环节,订单也是电商系统的核心数据…...
作为公司,这个5款在线软件工具赶紧安利起来!
2023年了 ,您的企业还没使用在线软件工具吗?自从用了在线工具之后,感觉打开了新办公世界的大门,效率蹭蹭蹭地往上涨啊。对于喜欢追求效率和便捷的我来说,在线实在是太棒了!今天安利几个非常不错的在线软件工…...
面试(七)为什么一般希望将析构函数定义为虚函数
class B { public:~B() // 基类析构函数不为虚函数{cout << "B::~B()" << endl;} };class D : public B { public:~D(){cout << "D::~D()" << endl;} };void Test(B* t) {delete t;t nullptr; }int main() {B *pb new B;Test…...
MySQL必会四大函数-时间函数
一、时间日期获取函数 获取当前日期(date)函数:curdate() mysql> select curdate(); 2023-02-09 获取当前时间(time)函数:curtime() select curtime(); 08:49:27 获取当前时间戳(date &…...
震惊!邻桌的程序猿做可视化报告竟然比我还快,带着好奇心我打开了他的电脑,发现惊天秘密,原因竟是...
其实,本文就是想分享一个做可视化的捷径! 制作可视化的方式有千千万。 Excel 控若能轻车熟路驾驭 VBA,能玩出各种花来,再不济借助图表插件外援也能秒杀一众小白选 手。 会编程的,Echarts 几十行代码,分分…...
mathtype7与word冲突,无法安装,不显示工具栏的问题解决
首先无法安装,或安装出错时,要清理注册表防止以后再次出现该问题,以此记录留作备份。打开注册表的方法是键盘winr键同时按(win就是Alt旁边像窗户图标的键),正常的话会跳出一个叫“运行”的家伙,…...
IBM AIX 升级Openssh 实现篇(编译安装)
升级成功佐证 !!!本文所有内容仅作参考,请在测试环境中具体测试完毕后才能应用于生产环境!!! [1]备份和恢复方案 开启telnet 服务,防止ssh 掉线后无法重连维护。在修复漏洞后关闭telnet。 备份该服务相关的所有文件,以便恢复。 root@TEST:/etc# vi inetd.conf #ftp…...
linux的睡眠框架及实现
睡眠 4 种模式:S2I (Suspend-to-Idle): 挂起系统,IO进入低功耗模式。需配置CONFIG_SUSPEND。Standby:执行S2I后,把AP (nonboot CPU) 离线。除了CONFIG_SUSPEND的支持外,还需要向suspend子系统注册ÿ…...
Java面试知识点
工作也有好些年了,从刚毕业到前几年看过无数的面试题,总想着自己写一个面试总结,随着自我认识的变化,一些知识点的理解也越来越不一样了。写下来温故而知新。很多问题可能别人也总结过,但是答案不尽相同,如…...
PTA Advanced 1159 Structure of a Binary Tree C++
目录 题目 Input Specification: Output Specification: Sample Input: Sample Output: 思路 代码 题目 Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and inorder traversal sequences, a binary tree can be un…...
CDN绕过技术总汇
注 本文首发于合天网安实验室 首发链接:https://mp.weixin.qq.com/s/9oeUpFUZ_0FUu6YAhQGuAg 近日HVV培训以及面试,有人问了CDN该如何绕过找到目标真实IP,这向来是个老生常谈的问题,而且网上大多都有,但是有些不够全面…...
算法训练营DAY51|300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组
本期是求子序列的新的一期,题目前两道有一些相似之处,思路差不多,第三道有一点难度,但并不意味着第一道没有难度,没有做过该类型题的选手,并不容易解出题解。 300. 最长递增子序列 - 力扣(Leet…...
mac:彻底解决-安装应用后提示:无法打开“XXX”,因为无法验证开发者的问题;无法验证此App不包含恶意软件
mac从浏览器或其他电脑接收了应用,但是打开报错 目录报错解决办法一次性方法永久解决方法验证恢复应用验证报错 截图如下: 错误信息 无法打开“XXX”,因为无法验证开发者的问题;无法验证此App不包含恶意软件 解决办法 一次性方…...
CPU 指标 user/idle/system 说明
从图中看出,一共有五个关于CPU的指标。分别如下: User User表示:CPU一共花了多少比例的时间运行在用户态空间或者说是用户进程(running user space processes)。典型的用户态空间程序有:Shells、数据库、web服务器…… Nice N…...
Thinkphp大型进销存ERP源码/ 进销存APP源码/小程序ERP系统/含VUE源码支持二次开发
框架:ThinkPHP5.0.24 uniapp 包含:服务端php全套开源源码,uniapp前端全套开源源码(可发布H5/android/iod/微信小程序/抖音小程序/支付宝/百度小程序) 注:这个是全开源,随便你怎么开,怎么来&a…...
怎么制作网站维护公告效果/新一轮疫情最新消息
微信开始严打第三方网页强制跳转行为,禁止使用提供诱导或强制点击跳转阅读全文功能,违规导流网站一律封杀!微信方面表示,近期大量用户投诉,在微信中打开第三方网站链接内容总是出现诱导或强制点击才能阅读链接全文行为,…...
新浪博客上传wordpress/北京网站制作推广
推荐引擎的分类 推荐引擎的分类可以根据很多指标,下面我们一一介绍一下: 推荐引擎是不是为不同的用户推荐不同的数据 根据这个指标,推荐引擎可以分为基于大众行为的推荐引擎和个性化推荐引擎 根据大众行为的推荐引擎,对每个用户…...
wordpress网易云音乐自定义css/在百度怎么创建自己的网站
序言最近准备搞搞硬件,略懂电子元器件、Python,主业PHP,准备写树莓派系列文章(从入门到放弃的那种),希望各位捧个人场。准备工作有动手能力的可以使用树莓派4B裸板,可以在某东和某宝买,也可购买套装带传感器…...
西安道桥建设有限公司网站/5118站长网站
商业计划书范文商业模式是项目成败的核心之一,也是投资者最关心的。在计划书中,商业模式部分主要是要说明你的企业是怎么赚钱的,小编今天为大家带来商业计划书范文,一起来看看吧!一、前言在这个“人才至上”的年代&…...
网站建设一个月做十单/网站入口百度
1 ,启动 zookeeper 命令 :( ) 2 ,查看 zookeeper 启动状态命令 :( ) 3 ,停止 zookeeper 命令 :( ) 4 ,动手题 :请编写老师在课上写的 3 个 shell 脚本,一键启动集群&…...
太原建站培训/网站监测
1)Boosting思想和基本概念 2)AdaBoost算法 3)AdaBoost算法举例 4)AdaBoost算法的解释——前向分步算法 5)提升树算法 6)提升树算法举例 1)Boosting思想和基本概念 下面的概念前面都讲过&…...