首页 > 其他分享 >[笔记]字符串哈希

[笔记]字符串哈希

时间:2024-07-29 16:40:42浏览次数:9  
标签:10 idx int 碰撞 笔记 哈希 字符串

定义

把一个字符串映射到一个整数的函数称作哈希函数,映射到的这个整数就是这个字符串的哈希值。

需要注意的一点是,哈希是将大空间上的东西(字符串有无穷多个)映射到了小空间(一定范围内的整数),所以必定会存在冲突,即若干个不同的字符串映射到了相同的哈希值,我们将这种冲突称作“哈希碰撞”。也就是说,不同哈希值的两个字符串一定不同,但相同哈希值的两个字符串也可能不同。

不过在大部分情况下,哈希碰撞发生概率很小。所以我们可以放心地用哈希来表示一个唯一的字符串,进而可以通过哈希值来比较两个字符串是否相等(这也是哈希最重要的性质)。

减少哈希碰撞概率的方法后面会提到。

多项式哈希函数

哈希函数有很多种,比较常用的是多项式类型(下面默认字符串下标从\(1\)开始):
\(f(s)=\sum\limits_{i=1}^{|s|}idx(s[i])*b^{n-i}\mod P\)
其中的\(idx(c)\)表示的是\(c\)这个字符的顺序,比如\(idx('a')=0,idx('z')=25\);
\(b\)是任意整数(一般取\(131,13331\)),而\(P\)是一个大素数(表示值域)。

子串哈希值快速计算

Libre OJ #103.子串查找

给定\(2\)个字符串\(A,B\),求\(B\)在\(A\)中的出现次数。
\(1\le |A|,|B|\le 10^6\)。

我们知道哈希值可以用于比较字符串是否相等,然而在这道题中如果我们暴力的计算\(A\)每个长度为\(|B|\)的子串哈希值,复杂度就是\(O(n^2)\),完全就是暴力嘛。

实际上,在我们计算\(A\)的哈希值过程中,可以换用递推的方式,用\(d[i]\)表示\(A\)的前\(i\)位的哈希值,则有:
\(d[i]=\begin{cases} 0&i=0\\ d[i-1]\times b+idx(s[i])&i>0 \end{cases}\)
那么\(s[l\sim r]\)的哈希值就是\(d[r]-d[l-1]\times b^{r-l+1}\),可以带入验证理解一下。

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define N 1000010
#define B 131
#define P 1000000007
using namespace std;
string a,b;
int n,m,d[N],powb[N],ans,fb;
int f(int l,int r){//计算a[l~r]的hash值
	return ((d[r]-d[l-1]*powb[r-l+1]%P)%P+P)%P;
}
signed main(){
	cin>>a>>b;
	n=a.size(),m=b.size();
	a=' '+a,b=' '+b;
	powb[0]=1;
	for(int i=1;i<=n;i++){
		d[i]=(d[i-1]*B%P+a[i]-'a')%P;
		powb[i]=powb[i-1]*B%P;
	}
	for(int i=1;i<=m;i++){
		fb=(fb*B%P+b[i]-'a')%P;
	}//因为b不用求子串hash,所以就不开数组了
	for(int i=1;i<=n-m+1;i++){
		if(f(i,i+m-1)==fb) ans++;
	}
	cout<<ans<<"\n";
	return 0;
}

哈希碰撞

我们试着计算一下哈希碰撞的概率:
假设值域为\(P\),有\(n\)个字符串,那么第\(i\)个字符串不碰撞的概率就是\(\frac{P-i+1}{P}\)。
相乘得到\(\prod\limits_{i=0}^{n-1}\frac{P-i}{P}\),这是\(n\)个字符串互不碰撞的概率。

通过计算,可以发现在\(P=10^9+7,n=10^6\)时概率约是\(6*10^{-218}\),也就是说几乎一定会发生碰撞。这个结论与生日悖论很相像(一个\(50\)人的班里,至少\(2\)人生日相同的概率大约是\(97\%\))。

当我们把值域\(P\)调至\(10^{18}+9\),不碰撞的概率达到了\(0.9999995\),此时碰撞几乎不可能发生,这与上面的结果是截然不同的。然而实际应用中我们常常不使用调大值域的方法,主要是因为容易爆long long,使用不方便。

我们一般用双哈希的方法,即使用两个不同的模数,比如\(10^9+7\)和\(10^9+9\)(都是质数)。这样值域就扩大到了两个模数的乘积,效果相同。

标签:10,idx,int,碰撞,笔记,哈希,字符串
From: https://www.cnblogs.com/Sinktank/p/18330416

相关文章

  • C#动态计算字符串中的表达式
    最近遇到一个需要计算字符串中表达式的需求,需要从字符串公式中动态计算结果。类似下面这样1stringexpression="Age*0.2+Height*0.1+log4"; 使用DataTable.Compute函数一开始找的是下面这种方法,但是不能计算对数1usingSystem.Data;23DataTabledt=ne......
  • 阿里云天池笔记
    一fromsklearn.model_selectionimporttrain_test_splitfromsklearn.linear_modelimportLinearRegressionfromsklearn.ensembleimportRandomForestRegressorimportpandasaspdimportzipfileimportreimportnumpyasnpimporttorch准备工作:安装sk......
  • hall 定理学习笔记
    万恶之源基本定义完美匹配是指最大匹配数为min(|X|,|Y|)也就是X或Y集合其中一个集合所有点都被匹配了。定理内容我们来假设X集合点少一点好了。X集合就当做有n个点。那么二分图G存在完美匹配,则取任意正整数1<=k<=n,均满足我从X集合选出k个不同的点,那么它们连向的y集合的点个......
  • Unity GameObject学习笔记
    GameObject成员变量GameObject静态方法//准备用来克隆的对象//1.直接是场景上的某个对象//2.可以是一个预制体对象publicGameObjectMyobj;#region知识点二GameObject中的静态方法创建自带几何体只要得到了一个GameObject对象我就......
  • 「FHQ-Treap —— 码量最小的平衡树」学习笔记
    不同于普通Treap,FHQ-Treap不需要左旋和右旋操作来处理数据。因此FHQ-Treap也称作无旋Treap。FHQ-Treap是基于Split(分裂)和Merge(合并)两种操作的平衡树。其与普通Treap的原理完全不同。一些基础的操作:例如Insert(插入元素)和Delete(删除元素)。对于Insert(插入元素),新建一......
  • LeetCode LCR 124.推理二叉树(哈希表 + 建树)
    某二叉树的先序遍历结果记录于整数数组 preorder,它的中序遍历结果记录于整数数组 inorder。请根据 preorder 和 inorder 的提示构造出这棵二叉树并返回其根节点。注意:preorder 和 inorder 中均不含重复数字。示例1:输入:preorder=[3,9,20,15,7],inorder=......
  • 自开发的哈希生成器(SHG)迎来 ULTRA 版本,内含新技术 SNF,详细介绍开发过程
     上链接:GitHub项目地址https://github.com/nitsc/Strong-Hash-Generator/tree/main/UltraCSDN上的介绍https://blog.csdn.net/zwa20110606/article/details/140708538**功能特点:****ULTRA版本**提供了以下功能:-使用了10层哈希算法: 1.SHA3-256   2.SHA3-5......
  • Living-Dream 系列笔记 第67期
    树上倍增:维护\(dp_{i,j}\)表示节点\(i\)向上移动\(2^j\)步所到达的节点编号、区间最值、区间和等信息。倍增求LCA:预处理:令\(dp_{i,j}\)表示\(i\)向上走\(2^j\)步所到达的节点。转移:\(dp_{i,j}=dp_{dp_{i,j-1},j-1}\)。初始:\(dp_{i,0}=fa_i\)。查询......
  • 【51单片机学习笔记】电动车自动报警项目(433M遥控)
    定义特殊功能位:使用sbit关键字定义了四个特殊功能位,这些位分别连接到单片机的I/O端口P1的第0到第3位。switcher用于控制继电器的开关,D0_ON和D1_OFF分别用于检测两个按键的状态,vibrate用于检测振动传感器的状态。延时函数:定义了两个延时函数Delay2000ms和Delay500ms,它们通......
  • 数据库第四天笔记
    命令行客户端windows:方式1:在电脑左下角搜索mysqlcommandclineclient点击进入输入密码按下回车即可方式2:进入到mysql的bin目录中C:\ProgramFiles(x86)\MySQL\MySQLServer5.1\bin在当前路径下输入cmd打开黑窗口输入:mysql-uroot-p按下回车输入......