数据结构之哈希——学习笔记

news2024/11/15 23:01:12

今天看网课学习了哈希的数据结构,写下这一篇博客记录自己的学习过程。

1.哈希简介:

 

我们发现某些时候映射到小集合的时候会同时有多个值映射到一个下标里面,所以接下来是这种情况的解决方案1: 

 我们考虑当两个数字映射之后的结果是在同一个下标的时候,那么不妨可以将第二个映射到这个下标的数字往后移动到第一个空白的下标里面。

实际上上面这一种解决问题的方式存在较大的问题,当冲突之后后移的话会导致对应下标里面的值不再是本身应该映射到这个下标里面的值了。

所以考虑到第一种值冲突解决问题在有些情况的不适用,那么接下来介绍第二种值冲突的解决方案:

接下来详细介绍vector(可以理解为动态数组): 

这样的方法可以理解为开设了多个链表,每个下标都相当于是一条链表,实际上虽然这种方法已经解决了绝大多数的问题但是当遇见特殊的样例,也就是样例映射之后全部都在一个下标的时候,一样是存在问题的。

接下来看一下哈希函数的设计:

 接下来看一下字符串如何进行哈希操作:

另外请思考: 

令base为11会导致值冲突加剧,另外发生值冲突我们考虑双哈希甚至三哈希等多次哈希操作来解决,也就是设置多个base以及p的值,这样的话只有当多组的base和p计算出来的值都相同的时候我们才会认为两个字符串相同。

 接下来看一下c++中自带的hash:

接下来来看一些例题:

 代码如下:

#include<bits/stdc++.h>
using namespace std;
int n,m;
const int P=9999971;//要模的素数
int a[200001],b[200001];
vector<int>c[P]; 
int main(){
	cin>>n>>m;//存下两篇论文的长度
	for(int i=0;i<P;i++)//将所有的链表数组清空
	c[i].clear();
	for(int i=1;i<=n;i++){
		cin>>a[i];
		c[a[i]%P].push_back(a[i]);//存下第一篇论文中所有的数字
	}
	int x=0;
	for(int i=1;i<=m;i++){
		cin>>b[i];
		bool ok=false;//假设这个数字不是抄袭的
		int v=b[i]%P;
		int l=c[v].size();
		//判断假设是否成立
		for(int j=0;j<l && !ok;j++)
			if(c[v][j]==b[i]) ok=true;
		if(ok) ++x;//如果成立 抄袭的部分加一
	}
	//判断被标记的抄袭的论文部分是否大于了一半
	if(2*x>=m) cout<<"Yes"<<endl;
	else cout<<"No"<<endl;
	return 0;
}
	

这里还有一种使用map的方法:

#include<bits/stdc++.h>
using namespace std;
int n,m;
const int P=9999973;
int a[200001],b[200001];
unordered_map<int,int>c;
int main(){
	cin>>n>>m;
	c.clear();
	for(int i=1;i<=n;i++){
		cin>>a[i];
		c[a[i]]=1;
	}
	int x;
	for(int i=1;i<=m;i++){
		cin>>b[i];
		if(c.find(b[i]) != c.end()) ++x;
	}
	if(x*2>=m) cout<<"Yes"<<endl;
	else cout<<"No"<<endl;
	return 0;
}

接下来再看第二个题:

 很明显这里是使用map,这是我的代码:

#include<bits/stdc++.h>
using namespace std;
int n,m;
unordered_map<string,int>a;
unordered_map<string,int>b;
unordered_map<string,int>c;
int main(){
	cin>>n>>m;
	a.clear();
	b.clear();
	c.clear();
	for(int i=1;i<=n;i++){
		string s;
		cin>>s;
		int x,y,z;
		cin>>x>>y>>z;
		a[s]=x;
		b[s]=y;
		c[s]=z;
	}
	for(int i=1;i<=m;i++){
		string s;
		cin>>s;
		if(a.find(s)==a.end()) cout<<"-1"<<' '<<"-1"<<" "<<"-1"<<endl;
		else cout<<a[s]<<' '<<b[s]<<' '<<c[s];
	}
	return 0;
}

但是会发现上面的代码使用了三个map来分别存身高年龄专业编码,实际上这三个都可以通过一个结构体来存储:

#include<bits/stdc++.h>
using namespace std;
int n,m;
struct Info{
	int x,y,z;
};
unordered_map<string,Info>a;
int main(){
	cin>>n>>m;
	a.clear();
	for(int i=1;i<=n;i++){
		string s;
		cin>>s;
		Info temp;
		cin>>temp.x>>temp.y>>temp.z;
		a[s]=temp;
	}
	for(int i=1;i<=m;i++){
		string s;
		cin>>s;
		if(a.find(s) != a.end()) cout<<a[s].x<<' '<<a[s].y<<' '<<a[s].z<<endl;
		else cout<<"-1"<<' '<<"-1"<<' '<<"-1"<<endl;
	}
	return 0;
}

ok,接下来看下一道题目:

#include<bits/stdc++.h>
using namespace std;
int n;
unordered_map<int,int>c;
int a[200001];
int main(){
	scanf("%d",&n);
	c.clear();
	for(int i=1;i<=n;i++){
		int x;
		cin>>x;
		++c[x];
	}
	int x=0,l=0;
	for(auto temp : c){
		if(temp.second>x){
		x=temp.second;
		l=0;
		}
		if(temp.second==x) a[++l]=temp.first;
	}
	sort(a+1,a+l+1);
	for(int i=1;i<=l;i++)
	cout<<a[i]<<' ';
	return 0;
}

 这道题目看似很简单实则还是有一定难度的。正常人思路肯定一开始都是利用数组来存储每个数字出现的次数然后最后遍历数组容量,更新出现次数最多的数字,如果遇上多个相同大的,那就利用一个数组和一个判断长度l的变量来进行不断更新和便于之后的输出。

接下来看第四题:

 代码如下:

#include<bits/stdc++.h>
using namespace std;
int n;
unordered_map<int,int>c;
int main(){
	cin>>n;
	c.clear();
	for(int i=1;i<=n;i++){
		int x;
		cin>>x;
		++c[x];
	}
	int x=0;
	bool add=false;
	for(auto temp : c){
		if(temp.second & 1) add=true;
		x+=temp.second/2*2;
	}
	if(add) ++x;
	cout<<x<<endl;
	return 0;
}

最后一个题目了:

 代码如下:

#include<bits/stdc++.h>
using namespace std;
int n,m;
const int p=9999973,base=101;
int ha[200010],hb[200010],c[200010];
char a[200010],b[200010];
int main(){
	scanf("%d%d",&n,&m);
	scanf("%s%s",a+1,b+1);
	c[0]=1;
	for(int i=1;i<=200000;i++)
	c[i]=c[i-1]*base%p;
	for(int i=1;i<=n;i++)
	ha[i]=(ha[i-1]*base+(a[i]-'a'))%p;
	for(int i=1;i<=m;i++)
	hb[i]=(hb[i-1]*base+(b[i]-'a'))%p;
	int ans=0;
	for(int i=1;i+m-1<=n;i++)
	if((ha[i+m-1]-1LL*ha[i-1]*c[m]%p+p)%p==hb[m])
	++ans;
	printf("%d\n",ans);
	return 0;
}

以上是一个单哈希的写法,c数组代表了base的i次方的值,而ha和hb分别包含了长度为i子串的哈希值最后一个for循环进行遍历计算有b子串在a子串出现了多少次。然后输出答案,接下来介绍一个双哈希的写法:

#include<bits/stdc++.h>
using namespace std;
int n,m;
const int p=9999973,base=101;
const int p2=9999973,base2=137;
int ha[200010],hb[200010],c[200010],c2[200011],ha2[200011],hb2[200011];
char a[200010],b[200010];
int main(){
	scanf("%d%d",&n,&m);
	scanf("%s%s",a+1,b+1);
	c[0]=1;c2[0]=1;
	for(int i=1;i<=200000;i++){
	c[i]=c[i-1]*base%p;
	c2[i]=c2[i-1]*base2%p2;
	}
	for(int i=1;i<=n;i++){
	ha[i]=(ha[i-1]*base+(a[i]-'a'))%p;
	ha2[i]=(ha2[i-1]*base2+(a[i]-'a'))%p2;
	}
	for(int i=1;i<=m;i++){
	hb[i]=(hb[i-1]*base+(b[i]-'a'))%p;
	hb2[i]=(hb2[i-1]*base2+(b[i]-'a'))%p2;
	}
	int ans=0;
	for(int i=1;i+m-1<=n;i++)
	if((ha[i+m-1]-1LL*ha[i-1]*c[m]%p+p)%p==hb[m] && (ha2[i+m-1]-1LL*ha2[i-1]*c2[m]%p2+p2)%p2==hb2[m])
	++ans;
	printf("%d\n",ans);
	return 0;
}

希望今天的学习记录笔记同样对读者有所帮助。

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

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

相关文章

用js计算 m-n 之间所有数的和

<script>let mprompt(输入小值)let nprompt(输入大值)function fn(min,max){let sum0for(let imin;i<max;i){sumi}return sum}let allfn(m,n)console.log(和&#xff1a;${all})</script> 效果&#xff1a;

Docker一键极速安装Nacos,并配置数据库!

1 部署方式 1.1 DockerHub javaedgeJavaEdgedeMac-mini ~ % docker run --name nacos \ -e MODEstandalone \ -e JVM_XMS128m \ -e JVM_XMX128m \ -e JVM_XMN64m \ -e JVM_MS64m \ -e JVM_MMS64m \ -p 8848:8848 \ -d nacos/nacos-server:v2.2.3 a624c64a1a25ad2d15908a67316d…

51单片机定时/计数器相关知识点

51单片机定时/计数器相关知识点 结构组成 51单片机的定时/计数器中有两个寄存器&#xff1a; T0&#xff1a;低位&#xff1a;TL0&#xff08;字节地址8AH&#xff09;高位&#xff1a;TH0&#xff08;字节地址8CH&#xff09;T1&#xff1a;低位&#xff1a;TL1&#xff08…

【java】期末复习知识点

简单不先于复杂&#xff0c;而是在复杂之后。 文章目录 填空题封装包主类开发过程的改变interfaceabstract class访问控制关键字继承多态object 类Java I/O(输入/输出)异常线程和进程创建线程的两种基本方法 编程题Hello World编写Swing程序&#xff0c;显示一个空白窗口 填空题…

代码随想录-刷题第四十八天

198. 打家劫舍 题目链接&#xff1a;198. 打家劫舍 思路&#xff1a;当前房屋偷与不偷取决于前一个房屋和前两个房屋是否被偷了。这里就更感觉到&#xff0c;当前状态和前面状态会有一种依赖关系&#xff0c;那么这种依赖关系都是动规的递推公式。动态规划五步曲&#xff1a;…

阿里云服务器 使用Certbot申请免费 HTTPS 证书及自动续期

前言 Certbot是一款免费且开源的自动化安全证书管理工具&#xff0c;由电子前沿基金会&#xff08;EFF&#xff09;开发和维护&#xff0c;是在Linux、Apache和Nginx服务器上配置和管理SSL/TLS证书的一种机制。Certbot可以自动完成域名的认证并安装证书。 一、 安装软件 1.1…

噬菌体序列分析工具PhaVa的使用和使用方法

github: 25280841/PhaVa: Adapting the phasefinder approach for identifying phase variation to long reads (github.com) 挺简单的&#xff0c;这里就不翻译了&#xff0c;大家看着直接用吧。 PhaVa PhaVa is an approach for finding potentially Phase Variable invert…

11.2 Linux串口驱动框架

tty 驱动程序框架 tty 驱动程序从下往上分别是设备驱动层、行规程、终端虚拟化、TTY I/O层&#xff0c;它们的功能如下&#xff1a; 设备驱动层&#xff1a;用于驱动设备&#xff0c;如串口、显示器、键盘等。行规程&#xff1a;用于处理控制字符、回显输入数据、缓存输入数据…

状态机(有限状态机(Finite State Machine, FSM)、推进自动机(Pushdown Automata)、并发状态机、分层状态机)

文章目录 状态机&#xff08;State Machine&#xff09;定义与组成定义组成状态&#xff08;States&#xff09;事件&#xff08;Events&#xff09;转换&#xff08;Transitions&#xff09;初始状态&#xff08;Initial State&#xff09; 状态机的类型有限状态机&#xff08…

Spark MLlib简介与机器学习流程

在大数据领域&#xff0c;机器学习是一个关键的应用领域&#xff0c;可以用于从海量数据中提取有价值的信息和模式。Apache Spark MLlib是一个强大的机器学习库&#xff0c;可以在分布式大数据处理环境中进行机器学习任务。本文将深入介绍Spark MLlib的基本概念、机器学习流程以…

MediaPipeUnityPlugin Win10环境搭建(22年3月的记录,新版本已完全不同,这里只做记录)

https://github.com/homuler/MediaPipeUnityPlugin You cannot build libraries for Android with the following steps. 1、安装msys2配置系统环境变量Path添加 C:\msys64\usr\bin 执行 pacman -Su 执行 pacman -S git patch unzip 2、安装Python3.9.10 勾选系统环境变量 …

LINUX服务器防火墙nf_conntrack问题一例

一、故障现象 业务反馈服务异常,无法响应请求&#xff0c;从系统日志 dmesg 或 /var/log/messages 看到大量以下记录&#xff1a;kernel: nf_conntrack: table full, dropping packet. 二、问题分析 业务高峰期服务器访问量大&#xff0c;内核 netfilter 模块 conntrack 相关参…

Docker 发布自定义镜像到公共仓库

Docker 发布自定义镜像到公共仓库 引言 Docker 是一种轻量级、便携式的容器化技术&#xff0c;可以使应用程序在不同环境中更加可移植。在本文中&#xff0c;我们将学习如何使用 Docker 从公共仓库拉取 Nginx 镜像&#xff0c;定制该镜像&#xff0c;添加自定义配置文件&…

1.4 SPEEDING UP REAL APPLICATIONS

我们从并行化应用程序中可以期待什么样的速度&#xff0c;这取决于应用程序中可以并行化的部分。如果可并行化部分所花费时间的百分比为30%&#xff0c;则并行部分的100倍加速将使执行时间减少不超过29.7%。整个应用程序的加速速度将仅为1.4倍左右。事实上&#xff0c;即使在并…

C语言编译器(C语言编程软件)完全攻略(第二十六部分:C-Free使用教程(使用C-Free编写C语言程序))

介绍常用C语言编译器的安装、配置和使用。 二十六、C-Free使用教程&#xff08;使用C-Free编写C语言程序&#xff09; 1、安装C-Free 5.0 C-Free 是一款国产的Windows下的C/C IDE&#xff0c;最新版本是 5.0&#xff0c;整个软件才 14M&#xff0c;非常轻巧&#xff0c;安装…

vue3项目中axios的常见用法和封装拦截(详细解释)

1、axios的简单介绍 Axios是一个基于Promise的HTTP客户端库&#xff0c;用于浏览器和Node.js环境中发送HTTP请求。它提供了一种简单、易用且功能丰富的方式来与后端服务器进行通信。能够发送常见的HTTP请求&#xff0c;并获得服务端返回的数据。 此外&#xff0c;Axios还提供…

大学物理-实验篇——测量误差与数据处理(测量分类、误差、有效数字、逐差法)

目录 测量分类 测量次数角度 测量条件角度 误差 误差分类 系统误差 随机误差 异常值 误差描述 精密度&#xff08;Precision&#xff09; 正确度&#xff08;Trueness&#xff09; 准确度/精确度&#xff08;Accuracy&#xff09; 随机误差的处理 直接测量 算术…

阻止持久性攻击改善网络安全

MITRE ATT&CK框架是一个全球可访问的精选知识数据库&#xff0c;其中包含基于真实世界观察的已知网络攻击技术和策略。持久性是攻击者用来访问系统的众多网络攻击技术之一;在获得初始访问权限后&#xff0c;他们继续在很长一段时间内保持立足点&#xff0c;以窃取数据、修改…

基于多反应堆的高并发服务器【C/C++/Reactor】(中)创建一个TcpConnection实例 以及 接收客户端数据

#CSDN 年度征文&#xff5c;回顾 2023&#xff0c;赢专属铭牌等定制奖品# 一、主线程反应堆模型的事件添加和处理详解 >>服务器和客户端建立连接和通信流程&#xff1a; 基于多反应堆模型的服务器结构图&#xff0c;这主要是一个TcpServer&#xff0c;关于HttpServer,…

目标检测-One Stage-EfficientDet

文章目录 前言一、EfficientNetEfficientNet-B0 baselineMBConv 参数优化EfficientNet B0-B7 参数 二、EfficientDetBiFPN复合缩放方法 总结 前言 EfficientDet是google在2019年11月发表的一个目标检测算法系列&#xff0c;其提出的背景是&#xff1a;之前很多研究致力于开发更…