.哈希表.

哈希

哈希表:将大而复杂的数据映射到紧凑的区间内。分为:①存储结构 

(离散化是特殊的哈希,之前讲的离散化是严格保序的 映射到区间上是连续递增的)


哈希不保序,这里讲的是一般的哈希

弊端:若数据的数值较大可以对其取模后再映射,但是取模后可能造成:
之前不相同的数值取模后映射到同一位置上了,所以引入:开放寻址法拉链法

①存储结构 

{


    1(开放寻址法


    {
    添加:
        开一个一维数组h[],长度一般要开到题目要求长度的2到3倍
        1'假设a取模后的值为k,那么就将a放到h[k]上
        2'若b取模后的值仍为k,那么就将b放到h[k+i]上(即向后遍历,直到找到一个没存放数值的h[k+i]为止)

注意:由于这里数组h[ ]的长度为题设要求的2~3倍,所以一定能找到一个位置满足上述1’,2’两种情况
        ...
    查找:
        如果当前h[k]存在并且h[k]==x那么就找到了,如果!=x那么就继续向下寻找
        如果当前h[k]不存在,那么就不需要向下寻找,即x不存在
    
    删除:
        不真正的删除,而是开一个bool类型的数组,将所要删除的数值标记一下
        后续在查询、添加操作时,对此值是否存在特判一下即可

题目:840. 模拟散列表 - AcWing题库

代码:

暴力+二分,样例11/16:
#include<bits/stdc++.h>using namespace std;const int N=1e5+50;
int f[N];int main()
{int n,i=0;scanf("%d",&n);while(n--){char op[5];int x;scanf("%s %d",op,&x);if(!strcmp(op,"I")){f[i]=x;i++;}else{sort(f,f+i);int l=0,r=i-1;while(l<r){int mid=l + r +1 >> 1;if(f[mid]>x) r=mid-1;else l=mid;}if(f[l]==x) cout << "Yes" << endl;else cout << "No" << endl;}}return 0;
}

 哈希:

#include<iostream>
//memset()函数所在头文件
#include<cstring>
using namespace std;
int n;
const int N=2e5+3,null=0x3f3f3f3f;
int h[N];//如果x在hash表中已经存在的话,就返回x在hash表中所在的位置
//如果不存在的话就返回x应该在hash表中存储的位置
int find(int x)
{int k=(x%N + N)%N;while(h[k]!=null && h[k]!=x){k++;//如果k==N的话(最边缘),那么就让它从头开始寻找//由于N的长度为题解要求的2倍,所以一定能找到一个k//这个k要么是x在hash表中的位置,要么是它可以在hash表中存在的位置if(k==N) k=0;}return k;}int main()
{scanf("%d",&n);memset(h,null,sizeof h);while(n--){char op[2];int x;scanf("%s %d",op,&x);int k=find(x);if(!strcmp(op,"I")) h[k]=x;//直接记录下x可以在hash表中插入的位置else{//如果x存在于hash表中,那么一定不等于null//如果不存在于hash表中,那么k所返回的值就是x可以在hash表中存在的位置//但是由于这一步是查询操作,所以h[k]==null(null是初始值)if(h[k]!=null) cout << "Yes" << endl;else cout << "No" << endl;}}return 0;
}

}

2(拉链法

{
    添加:
        开一个一维数组a[]存下所有数值,将数值a取模后的值(假设是3),
        就在数组a[3]的后面 “拉一条链” 将a链住
        如果又有数值b取模后仍等于3,那么就在数值a的后面再“拉一条链”将数值b链住
        (每个数组a[]下对应的链就是我们之前所学的单链表)

插入过程与前面链表的插入过程一致,可翻阅查看:.单链表.-CSDN博客


        ...
    查找:
        求出数值取余后对应的是数组a[]上的那一个值,再询问此a[]上的链表是否有所要求的数值
    删除:
        不真正的删除,而是开一个bool类型的数组,将所要删除的数值标记一下
        后续在查询、添加操作时,对此值是否存在特判一下即可

代码:

#include<iostream>
//memset()函数所在头文件
#include<cstring>
using namespace std;
int n;
const int N=1e5+3;
int h[N],e[N],ne[N],idx;void insert(int x)
{//取模,映射到数组h[]上,x可能为负数,所以先模再加 之后再次取模int k=(x%N+N)%N;e[idx]=x,ne[idx]=h[k],h[k]=idx,idx++;
}bool find(int x)
{int k=(x%N + N)%N;//遍历链表h[k](链表上的第一个下标)表示数组上下标为k的下一个指向//每次让i指向它的下一个指向(移动指针i,使其继续向下遍历)//i=-1时即遍历结束(空值)for(int i=h[k];i!=-1;i=ne[i])if(e[i]==x)return true;return false;
}int main()
{scanf("%d",&n);memset(h,-1,sizeof h);while(n--){char op[2];int x;scanf("%s %d",op,&x);if(!strcmp(op,"I")) insert(x);else{if(find(x)) cout << "Yes" << endl;else cout << "No" << endl;}}
return 0;
}

}

取模的值:

上述的N分别取的是N=2e5+3、1e5+3这里不像之前取1e5+10是因为:N是取模的值

取模的值一般满足以下规律使映射时的重复率最低:(取模的数值一般取成质数并且离2的整次幂要远的多)

计算方法:
(取模的数值一般取成质数并且离2的整次幂要远的多)
{//本题的操作次数不大于100000,所以从100000开始遍历(根据题设要求来初始化i)for(int i=100000;;i++){bool flag=true;for(int j=2;j*j<=i;j++)if(i%j==0){flag=false;break;}if(flag){cout << i << endl;break;}}return 0;//这里输出的i就是接下来要取模的数值
}

②字符串哈希方式

字符串hash方式
    这里讲的是特殊的hash方式:字符串前缀哈希法
    类似于前缀和:
    {
    str="abcacwing",str[0]=0(特殊处理),str[1]="a",str[2]="ab",
    str[3]="abc",str[4]="abca"...
    定义某一个哈希的前缀和:把这个字符串看成是p进制的数
    每一位字母(str[i])看成是在p进制下的数字
    如果字符串str[4]="abcd",分别在p进制下,a:1,b:2,c:3,d:4

    那么str[4]在p进制下的和即为:1*p^3+2*p^2+3*p^1+4*p^0,
    这样处理就可以把字符串转化成一个数字
    但这个数字可能较大,所以mod(%)上一个数Q,那么就可以把这个大的数字映射成1~Q-1之内的数字了。

接下来通过比较数值大小即可比较两个字串是否相同。

注意:①:不能映射成0,因为0在任何进制下的值都为0,那么字符串:aasxas,axssx,cbdhd都会被映射成0
    ②:这里是假设不存在冲突,不存在重复的情况。当p=131或者13331,Q=2^64时,基本上不存在冲突
    若要模上Q(2^64)那么可以直接用unsigned long long 来存储hash值,溢出的值就是模上2^64的值。

}

这样处理的好处就是可以利用前缀哈希,来确定任意字串的哈希值

{
    这里的左边(1)是高位,右边(R)是低位(进制情况下最左边为最低位,即最左边*P^0)。所以在h[R]中R就是第0位,1就是第R-1位,h[l-1]中l-1就是第0位,1就是第l-2位。

那么如果要求L到R之间字串的hash值,那么就先要将h[l-1]的0位与h[R]的第0位对齐
这里R在l的右边,所以改变h[l-1]的0位与h[R]的第0位对齐
(不对齐0位,由于不同数位对应不同P的幂,那将导致相减毫无意义)
 比如:1*p^3+2*p^2+3*p^1+4*p^0,数位a对应的是P^3,b对应的是P^2..                                          即将h[l-1]*((P^(R-1))/(P^(l-2))

}

也就是达到数位对齐的目的字符串ABCDE 与 ABC 的前三个字符值是一样,只差两位,
乘上P的二次方把 ABC 变为 ABC00,再用 ABCDE - ABC00 得到 DE 的哈希值。
   

最终所推得的公式:


子串的hash值为①:h[R]-h[l-1](P^(R-L+1));

所以最终任意字符串的hash值为②:h[i]=h[i-1]*P + str[i];

公式①:

公式②:

题目:841. 字符串哈希 - AcWing题库

代码:

暴力+双指针,样例:8/13:
#include<iostream>using namespace std;int main()
{int m,n;scanf("%d %d",&m,&n);char str[100050];scanf("%s",str);while(n--){int x1,y1,x2,y2;scanf("%d %d %d %d",&x1,&y1,&x2,&y2);bool flag=true;while(x1<=y1 && x2<=y2){if(str[x1-1]!=str[x2-1] ||str[y1-1] != str[y2-1]){flag=false;break;}else x1++,x2++,y1--,y2--;}if(flag) printf("Yes\n");else printf("No\n");}
}

 哈希字符串:

#include<bits/stdc++.h>using namespace std;typedef unsigned long long ULL;
const int N=1e5+10,P=131;int n,m;
char str[N];
//p[]是对进制P的预处理,记录了P的不同幂次方
//h[]存放的是该字符串的每一个字母对应的hash值
ULL h[N],p[N];int get(int l,int r)
{return h[r]-h[l-1]*p[r-l+1];
}
int main()
{scanf("%d%d%s",&n,&m,str+1);p[0]=1;for(int i=1;i<=n;i++){
//这里需要多次运用到P的幂次方,所以在此提前做预处理//预处理,这里溢出值相当于取模后的值p[i]=p[i-1]*P;//转换成P进制下的数h[i]=h[i-1]*P+str[i];}while(m--){int l1,r1,l2,r2;scanf("%d%d%d%d",&l1,&r1,&l2,&r2);if(get(l1,r1)==get(l2,r2)) printf("Yes\n");else printf("No\n");}return 0;}

tips:

注意上述所给出的一些小技巧,能更好的帮助理解。

而且比如:p[i]=p[i-1]*P;很好的避免了pow(P,i)的繁杂操作

倘若还是不理解就先将公式记下来

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

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

相关文章

Linux(四)

Linux&#xff08;四&#xff09; shell脚本shell脚本开发过程创建创建.sh文件编写.sh文件添加执行的权限 chmod 777 1.sh运行 shell中注释shell中变量用户自定义变量 (尽量大写)位置参数即命令行参数预定义变量环境变量 shell中程序和语句说明性语句功能性语句echo 输出read 键…

网上打印试卷的步骤是什么

对于学生和家长来说&#xff0c;打印试卷是日常学习中的一项重要需求。那么&#xff0c;如何在网上方便地打印试卷呢&#xff1f;下面&#xff0c;就让我来为您介绍琢贝云打印的试卷打印步骤。 一、选择琢贝云打印的原因 支持多种文件格式打印&#xff0c;包括图片、PPT、PDF、…

每日百万交易的支付系统,如何设置JVM堆内存大小?

每日百万交易的支付系统,如何设置JVM堆内存大小? 1、支付背景的引入2、支付的核心业务流程3、每日百万交易支付系统的压力在哪里?4、支付系统每秒钟需要处理多少笔支付单5、每个支付订单处理需要耗时多久6、每个支付订单大概需要多大的内存空间7、每秒发起的支付请求对内存的…

手撕C语言题典——消失的数字

目录 前言 一&#xff0c;思路 1)排序查找 2&#xff09;数据求和&#xff0c;依次减去中值 3&#xff09; 异或 二&#xff0c;异或的代码实现 前言 依旧是一道力扣上的题&#xff0c;通过不同思路的不同时间复杂度来分析&#xff0c;让我们看看有什么不同。 面试题 17…

贪心-ACW803区间合并-XMUOJ力量碎片合并

题目 思路 附上几个参考链接 for(auto i : v)遍历容器元素_for auto 遍历-CSDN博客 C pair的基本用法总结&#xff08;整理&#xff09;_c pair用法-CSDN博客 使用 sort 实现自定义排序 - AcWing 话不多说&#xff0c;直接上代码 代码 /* ACW803区间合并-XMUOJ力量碎片合…

第13章-循迹功能 循迹小车讲解 原理分析 STM32智能小车循迹教程 红外对管使用 PID循迹算法分析

讲解一下我们小车里面的循迹部分&#xff0c;包括红外基础使用&#xff0c;无PID循迹和有PID循迹。 第13章-循迹功能 13.1-非PID循迹功能完成 先红外对管调试 我们这里学习一下&#xff0c;如何实现循迹功能 如何才能让小车沿着黑线运动、要让小车感知到黑线的位置&#x…

C/C++ vector详解

要想了解STL&#xff0c;就必须会看&#xff1a; cplusplus.comhttps://legacy.cplusplus.com/ 官方内容全都是英文的&#xff0c;可以参考&#xff1a; C/C初始识https://blog.csdn.net/2301_77087344/article/details/138596294?spm1001.2014.3001.5501 vector&#xff…

sql聚合函数使用-笔记

sql聚合函数使用-笔记 SELECT SUM ( case when procurement_type 公益推送 then 1 else 0 end ) gywxTotal,SUM ( CASE WHEN (status 1 and procurement_type 公益推送) THEN 1 ELSE 0 END ) gywxYsc,SUM ( CASE WHEN (status ! 1 and procurement_type 公益推送) THEN 1 …

辐射度技术在AI去衣中的魅力与科学

引言&#xff1a; 在当今的数字化时代&#xff0c;人工智能正逐渐渗透到我们生活的方方面面。其中&#xff0c;AI去衣技术作为一项颇具争议但又不失其科技创新的应用&#xff0c;正引起越来越多的关注和讨论。而在实现高质量图像渲染的过程中&#xff0c;辐射度技术凭借其卓越的…

CAD二次开发(5)-用户交互仿系统命令

1. 工具类&#xff1a;PromptTool.cs using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace _04用户交互 {public static…

GEE26:批量导出逐日、逐月、逐季节和逐年的遥感影像(以NDVI为例)

影像导出 写在前面1.逐日数据导出2.逐月数据导出3.季节数据导出4.逐年数据导出 写在前面 最近很多小伙伴们私信我&#xff0c;问我如何高效导出遥感数据&#xff0c;从逐日到逐季度&#xff0c;我都有一套自己的方法&#xff0c;今天就来和大家分享一下&#xff01;   &#…

基于YOLOv8+PySide6的快递分类管理系统

1、背景 随着电子商务的飞速发展&#xff0c;快递行业所承受的数据处理需求愈发庞大。在这样的背景下&#xff0c;传统的手工分类方法已经显得力不从心&#xff0c;因其不仅耗时耗力&#xff0c;还存在着易出错的隐患。因此&#xff0c;迫切需要研发出一套高效而准确的自动化系…

多线程案例(线程池)

White graces&#xff1a;个人主页 &#x1f649;专栏推荐:Java入门知识&#x1f649; &#x1f649; 内容推荐:<计算坤是如何工作的>&#x1f649; &#x1f439;今日诗词:百年兴衰皆由人, 不由天&#x1f439; ⛳️点赞 ☀️收藏⭐️关注&#x1f4ac;卑微小博主&…

go 微服务框架kratos使用中间件的方法

一、中间件的概念 在go语言中&#xff0c;中间件是一种用于处理http请求的开发模式&#xff0c;允许开发人员在请求到达处理程序之前或之后执行特定的操作&#xff0c;如日志记录、身份验证、错误处理等。 中间件通常是一个函数&#xff0c;它接收一个 http.Handler 作为参数…

Ardupilot开源代码之Rover上路 - 后续4

Ardupilot开源代码之Rover上路 - 后续4 1. 源由2. 深度配置2.1 设置倒车按钮2.1.1 前进2.1.2 倒退 2.2 MP无法连接ESP82662.3 最小油门校准 3. 遗留&后续3.1 高精度编码器问题3.2 OV5647 720P30FPS 马赛克问题 4. 参考资料 1. 源由 开源项目最主要的问题就是所有配置是开放…

信息安全从运维到运营:CISAW安全运维方向

随着数据中心规模扩大&#xff0c;安全运维内生需要逐渐向安全运营进化&#xff0c;统一安全理念&#xff0c;提高服务意识&#xff0c;提升专业能力。安全运营是对安全运维的继承式发展&#xff0c;而不是颠覆&#xff0c;意味着以业务发展为基础&#xff0c;以事件核查为线索…

【gradle】MAC下用gradle构建部署springboot项目

MAC下用gradle构建部署springboot项目 前言下载安装配置gradle下载安装下载可能出现的问题 &#xff08;zsh: command not found: brew&#xff09; 配置环境变量配置国内下载源全局配置单个项目配置 通过idea构建项目构建后的项目结构 小结延伸 前言 好久以前就听说gradle了&…

RAG概述(一):RAG架构的演进

目录 概述 RAG核心步骤 Indexing索引 Retrieval检索 Generation生成​​​​​​​ Native RAG Advanced RAG Modular RAG 参考 概述 RAG&#xff1a;Retrieval-Augmented Generation 检索增强生成。 RAG通过结合LLMs的内在知识和外部数据库的非参数化数据&#xff…

与MySQL的初相遇

&#x1f30e;初识MySQL 注&#xff1a;本文SQL语句只为了验证猜想&#xff0c;不会也不要紧。 文章目录&#xff1a; MySql开端 认识数据库       什么是数据库       主流数据库       MySQL的本质 MySQL基础使用       连接mysql服务器     …

自动化您的任务——crewAI 初学者教程

今天&#xff0c;我写这篇文章是为了分享您开始使用一个非常流行的多智能体框架所需了解的所有信息&#xff1a;crewAI。 我将在这里或那里跳过一些内容&#xff0c;使本教程成为一个精炼的教程&#xff0c;概述帮助您入门的关键概念和要点 今天&#xff0c;我写这篇文章是为了…