哈希表2s总结

3.哈希表

哈希表非常常用,字典一般会用来保存处理过后的输入输出信息,集合也可以用来去重,这部分是重点,但是还是那句话,这种题目是不会或者说很少考原题的,主要还是学习知识,所以题目看一下答案理解一下知识就过了,不要纠结会不会出原题。

哈希表理论基础

哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素,如下图所示:

image-20240404112713269

⼀般哈希表都是⽤来快速判断⼀个元素是否出现集合⾥。
例如要查询⼀个名字是否在这所学校⾥。
要枚举的话时间复杂度是O(n),但如果使⽤哈希表的话, 只需要O(1)就可以做到。
我们只需要初始化把这所学校⾥学⽣的名字都存在哈希表⾥,在查询的时候通过索引直接就可以知道这位同学在不
在这所学校⾥了。
将学⽣姓名映射到哈希表上就涉及到了hash function ,也就是哈希函数。

哈希函数

哈希函数,把学⽣的姓名直接映射为哈希表上的索引,然后就可以通过查询索引下标快速知道这位同学是否在这所
学校⾥了。
哈希函数如下图所示,通过hashCode把名字转化为数值,⼀般hashcode是通过特定编码⽅式,可以将其他数据格
式转化为不同的数值,这样就把学⽣名字映射为哈希表上的索引数字了。

image-20240404113107435

存在两种情形

1.如果hashCode得到的数值⼤于 哈希表的⼤⼩了,也就是⼤于tableSize了

此时为了保证映射出来的索引数值都落在哈希表上,我们会在再次对数值做⼀个取模的操作,就要我们就保证了学
⽣姓名⼀定可以映射到哈希表上了。

2.哈希表我们刚刚说过,就是⼀个数组。如果学⽣的数量⼤于哈希表的⼤⼩怎么办,此时就算哈希函数计算的再均匀,也避免不了会有⼏位学⽣的名字同时映射到哈希表 同⼀个索引下标的位置。这会引起哈希碰撞

image-20240404113330027

⼀般哈希碰撞有两种解决⽅法, 拉链法和线性探测法。

拉链法
刚刚⼩李和⼩王在索引1的位置发⽣了冲突,发⽣冲突的元素都被存储在链表中。 这样我们就可以通过索引找到⼩
李和⼩王了(数据规模是dataSize, 哈希表的⼤⼩为tableSize)

image-20240404113617940

其实拉链法就是要选择适当的哈希表的⼤⼩,这样既不会因为数组空值⽽浪费⼤量内存,也不会因为链表太⻓⽽在
查找上浪费太多时间。

线性探测法
使⽤线性探测法,⼀定要保证tableSize⼤于dataSize。 我们需要依靠哈希表中的空位来解决碰撞问题。
例如冲突的位置,放了⼩李,那么就向下找⼀个空位放置⼩王的信息。所以要求tableSize⼀定要⼤于dataSize ,
要不然哈希表上就没有空置的位置来存放 冲突的数据了。如图所示

image-20240404113719050

常⻅的三种哈希结构

当我们想使⽤哈希法来解决问题的时候,我们⼀般会选择如下三种数据结构。
数组
set (集合)
map(映射)
这⾥数组就没啥可说的了,我们来看⼀下set。
在C++中,set 和 map 分别提供以下三种数据结构,其底层实现以及优劣如下表所示:

image-20240404113900727

std::unordered_set底层实现为哈希表,std::set 和std::multiset 的底层实现是红⿊树,红⿊树是⼀种平衡⼆叉搜
索树,所以key值是有序的,但key不可以修改,改动key值会导致整棵树的错乱,所以只能删除和增加。

image-20240404113936295

std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底层实现是红⿊树。同理,std::map 和
std::multimap 的key也是有序的(这个问题也经常作为⾯试题,考察对语⾔容器底层的理解)。

当我们要使⽤集合来解决哈希问题的时候,优先使⽤unordered_set,因为它的查询和增删效率是最优的,如果需
要集合是有序的,那么就⽤set,如果要求不仅有序还要有重复数据的话,那么就⽤multiset。

那么再来看⼀下map ,在map 是⼀个key value 的数据结构,map中,对key是有限制,对value没有限制的,因
为key的存储⽅式使⽤红⿊树实现的。

虽然std::set、std::multiset 的底层实现是红⿊树,不是哈希表,std::set、std::multiset 使⽤红⿊树来索引和存
储,不过给我们的使⽤⽅式,还是哈希法的使⽤⽅式,即key和value。所以使⽤这些数据结构来解决映射问题的⽅
法,我们依然称之为哈希法。 map也是⼀样的道理。
这⾥在说⼀下,⼀些C++的经典书籍上 例如STL源码剖析,说到了hash_set hash_map,这个与unordered_set,
unordered_map⼜有什么关系呢?

实际上功能都是⼀样⼀样的, 但是unordered_set在C++11的时候被引⼊标准库了,⽽hash_set并没有

image-20240404114458583

总结

总结⼀下,当我们遇到了要快速判断⼀个元素是否出现集合⾥的时候,就要考虑哈希法。
但是哈希法也是牺牲了空间换取了时间,因为我们要使⽤额外的数组,set或者是map来存放数据,才能实现快速
的查找。
如果在做⾯试题⽬的时候遇到需要判断⼀个元素是否出现过的场景也应该第⼀时间想到哈希法!

哈希表套路总结

数组作为哈希表

⼀些应⽤场景就是为数组量身定做的。
在242.有效的字⺟异位词中,我们提到了数组就是简单的哈希表,但是数组的⼤⼩是受限的!
这道题⽬包含⼩写字⺟,那么使⽤数组来做哈希最合适不过。
在383.赎⾦信中同样要求只有⼩写字⺟,那么就给我们浓浓的暗示,⽤数组!
本题和242.有效的字⺟异位词很像,242.有效的字⺟异位词是求 字符串a 和 字符串b 是否可以相互组成,在383.赎
⾦信中是求字符串a能否组成字符串b,⽽不⽤管字符串b 能不能组成字符串a。
⼀些同学可能想,⽤数组⼲啥,都⽤map不就完事了。
上⾯两道题⽬⽤map确实可以,但使⽤map的空间消耗要⽐数组⼤⼀些,因为map要维护红⿊树或者符号表,⽽
且还要做哈希函数的运算。所以数组更加简单直接有效!

set作为哈希表

在349. 两个数组的交集中我们给出了什么时候⽤数组就不⾏了,需要⽤set。
这道题⽬没有限制数值的⼤⼩,就⽆法使⽤数组来做哈希表了。
主要因为如下两点:
数组的⼤⼩是有限的,受到系统栈空间(不是数据结构的栈)的限制。
如果数组空间够⼤,但哈希值⽐较少、特别分散、跨度⾮常⼤,使⽤数组就造成空间的极⼤浪费。
所以此时⼀样的做映射的话,就可以使⽤set了。
关于set,C++ 给提供了如下三种可⽤的数据结构:(详情请看关于哈希表,你该了解这些!)
std::setstd::multiset
std::unordered_set
std::set和std::multiset底层实现都是红⿊树,std::unordered_set的底层实现是哈希, 使⽤unordered_set 读写效
率是最⾼的,本题并不需要对数据进⾏排序,⽽且还不要让数据重复,所以选择unordered_set。
在202.快乐数中,我们再次使⽤了unordered_set来判断⼀个数是否重复出现过。

map作为哈希表

在1.两数之和中map正式登场。
来说⼀说:使⽤数组和set来做哈希法的局限。
数组的⼤⼩是受限制的,⽽且如果元素很少,⽽哈希值太⼤会造成内存空间的浪费。
set是⼀个集合,⾥⾯放的元素只能是⼀个key,⽽两数之和这道题⽬,不仅要判断y是否存在⽽且还要记录y的
下标位置,因为要返回x 和 y的下标。所以set 也不能⽤。
map是⼀种 <key, value> 的结构,本题可以⽤key保存数值,⽤value在保存数值所在的下标。所以使⽤map最
为合适。
C++提供如下三种map::(详情请看关于哈希表,你该了解这些!)
std::map
std::multimap
std::unordered_map
std::unordered_map 底层实现为哈希,std::map 和std::multimap 的底层实现是红⿊树。
同理,std::map 和std::multimap 的key也是有序的(这个问题也经常作为⾯试题,考察对语⾔容器底层的理
解),1.两数之和中并不需要key有序,选择std::unordered_map 效率更⾼!
在454.四数相加中我们提到了其实需要哈希的地⽅都能找到map的身影。
本题咋眼⼀看好像和18. 四数之和,15.三数之和差不多,其实差很多!
关键差别是本题为四个独⽴的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不⽤考虑重复问题,⽽18. 四数
之和,15.三数之和是⼀个数组(集合)⾥找到和为0的组合,可就难很多了!
⽤哈希法解决了两数之和,很多同学会感觉⽤哈希法也可以解决三数之和,四数之和。
其实是可以解决,但是⾮常麻烦,需要去重导致代码效率很低。
在15.三数之和中我给出了哈希法和双指针两个解法,⼤家就可以体会到,使⽤哈希法还是⽐较麻烦的。
所以18. 四数之和,15.三数之和都推荐使⽤双指针法!

双指针法一定要排序,一旦排序后原来数组的索引就被改变

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/793332.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何保证Redis的缓存和数据库中的数据的一致性?

Redis的缓存如何和数据库中的数据保持一致性&#xff1f; 我们都知道&#xff0c;Redis是一个基于内存的键值存储系统&#xff0c;数据完全存放在内存中&#xff0c;这使得它的读写速度远超传统的硬盘存储数据库。对于高访问频率、低修改率的数据&#xff0c;通过将它们缓存在…

python csv 工具包的使用

1. Introduction a. what’s csv CSV文件是一种纯文本文件&#xff0c;用于存储表格数据。CSV是Comma-Separated Values的缩写&#xff0c;意为逗号分隔值。每一行表示表格中的一条记录&#xff0c;而每个字段之间用逗号分隔。CSV文件可以用文本编辑器打开并编辑&#xff0c;…

intellij idea 使用git ,快速合并冲突

可以选择左边的远程分支上的代码&#xff0c;也可以选择右边的代码&#xff0c;而中间是合并的结果。 一个快速合并冲突的小技巧&#xff1a; 如果冲突比较多&#xff0c;想要快速合并冲突。也可以直接点击上图中 Apply non-conflicting changes 旁边的 All 。 这样 Idea 就会…

2024-04-04 问AI: 在深度学习中,微调是什么?

文心一言 在深度学习中&#xff0c;微调&#xff08;Fine-tuning&#xff09;是一种训练策略&#xff0c;特别针对预训练模型进行。预训练模型通常是在大规模无标注数据上通过自监督学习得到的&#xff0c;它们已经具备了对一般自然语言结构或视觉特征的良好理解能力。微调则是…

深入浅出 -- 系统架构之垂直架构

当业务复杂度增加、访问量逐渐增大出现高并发时&#xff0c;单体架构无法满足需求&#xff0c;可以根据业务功能对系统进行拆分&#xff0c;以提高访问效率。 垂直架构介绍 1.垂直架构一般是因为单体架构太过于庞大而进行的拆分&#xff0c;拆分后各个系统应满足独立运行互相不…

wordpress外贸独立站模板

wordpress外贸独立站模板 WordPress Direct Trade 外贸网站模板&#xff0c;适合做跨境电商的外贸公司官方网站使用。 https://www.waimaoyes.com/wangzhan/22.html

【Android Studio】上位机-安卓系统手机-蓝牙调试助手

【Android Studio】上位机-安卓系统手机-蓝牙调试助手 文章目录 前言AS官网一、手机配置二、移植工程三、配置四、BUG五、Java语言总结 前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 AS官网 AS官网 一、手机配置 Android Studio 下真机调试 …

算法| ss 二分

34.在排序数组中查找元素的第一个和最后一个位置35.搜索插入69.x的平方根875.爱吃香蕉的珂珂 34.在排序数组中查找元素的第一个和最后一个位置 /*** param {number[]} nums* param {number} target* return {number[]}*/ // 思路 // 新建一个search函数&#xff0c;参数为是否…

unity学习(82)——profiler 限制帧率

实际测试发现当玩家个数增加时&#xff0c;客户端明显变的很卡&#xff0c;想知道为什么变卡了&#xff01; 1.只有玩家自己的时候 2.两个时候感觉脚本的工作量增大了 拖了一会直接炸了&#xff01;&#xff08;数据包积压把内存搞炸&#xff0c;我第一次见&#xff09; 3.我觉…

数据库的介绍分类作用特点

目录 1.概述 2.分类 2.1.关系型数据库 2.2.非关系型数据库 2.3.分布式数据库 ​​​​​​​2.4.云数据库 3.作用 4.特点 5.应用举例 5.1.MySQL ​​​​​​​5.1.1.作用 ​​​​​​​5.1.2.特点 ​​​​​​​5.1.3.应用案例 ​​​​​​​5.2.达梦 ​​​…

上位机图像处理和嵌入式模块部署(qmacvisual之tcp服务器端)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 上面一篇&#xff0c;我们谈到了tcp客户端&#xff0c;另外一种连接方法就是tcp服务器端。事实上&#xff0c;对于第三方系统&#xff0c;大多数情…

Python进阶:使用requests库轻松发送HTTP请求并获取响应

Python进阶&#xff1a;使用requests库轻松发送HTTP请求并获取响应 简介&#xff1a;本文将带您深入了解Python中强大的requests库&#xff0c;学会如何使用它发送各种HTTP请求&#xff0c;并轻松获取响应内容。无论您是初学者还是有一定经验的Python开发者&#xff0c;本文都…

ES10 学习

文章目录 1. Object.fromEntries()2. trimStart() 和 trimEnd()3. 数组的flat() 和flatMap()4. Symbol 对象的description 属性5. try ... catch(e){} 1. Object.fromEntries() Object.fromEntries() 方法允许你轻松地将键 值对列表转换为对象 let arr [["name",&qu…

《搜广推算法指南》(2024版) 重磅发布!

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学&#xff0c;针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 结合…

Linux系统NVME SSD上下电流程梳理

对NVMe SSD在Linux系统中执行上下电操作&#xff0c;涉及到硬件层面的电源管理以及与操作系统驱动程序的交互。以下是一个结合NVMe驱动代码原理与PCIe寄存器等信息的详细步骤说明&#xff1a; 上下电操作概述 上电操作&#xff1a;当Linux系统启动或热插拔NVMe SSD时&#xff0…

城市道路井盖破损丢失目标检测数据集VOC-1377张

数据集格式&#xff1a;Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件&#xff0c;仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数)&#xff1a;1377 标注数量(xml文件个数)&#xff1a;1377 标注类别数&#xff1a;4 标注类别名称:["jg","jg…

MuJoCo 入门教程(三)Python 绑定

系列文章目录 前言 从 2.1.2 版开始&#xff0c;MuJoCo 附带使用 pybind11 以 C 开发的本地 Python 绑定。Python API 与底层的 C API 保持一致。这导致了一些非 Python 代码结构&#xff08;如函数参数的顺序&#xff09;&#xff0c;但其好处是 API 文档适用于两种语言。 Pyt…

devtool: ‘source-map‘ 和 devtool: ‘#source-map‘的区别

devtool: ‘source-map’ 和 devtool: ‘#source-map’ 之间的区别主要在于前面的#字符。 从Webpack 4开始&#xff0c;就废弃了在devtool选项前加#的用法。 devtool: ‘source-map’ 选项意味着Webpack在构建过程中会生成独立的完整的source map文件。对于测试环境很有用&…

(React组件基础)前端八股文修炼Day6

一 类组件与函数组件有什么异同 在React中&#xff0c;类组件和函数组件是创建组件的两种主要方式。随着React的发展&#xff0c;尤其是自Hooks在React 16.8中引入以来&#xff0c;函数组件的功能变得更加强大&#xff0c;使得它们能够更加方便地与类组件相竞争。下面是类组件…

Collection与数据结构 Stack与Queue(一): 栈与Stack

1. 栈 1.1 概念 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&…