字符串哈希 详解+例题
字符串哈希
update 2024,10,6 添加一道题
观看讲解视频:董晓算法 做的笔记
理论部分
字符串哈希 是把不同的字符串映射成不同的整数。
-
对于一个长度为
的字符串 ,我们定义它的 Hash 函数为:
例如:字符串 ,他的 hash 函数值为
即 -
如果两个字符串不一样,Hash 值却一样,这样的现象称为 哈希碰撞
-
解决哈希碰撞的方法:
保证 、 互质, 通常取质数 或 ; 通常取大整数 ,哈希函数要定义为 ULL(unsigned long long),超过则自动溢出,等价于取模。
关于 unsigned long long:无符号,取值范围在
代码实现:
- 求一个字符串的哈希值:前缀和,
前缀和: , ( 表示前 项的 hash 值)
时间复杂度: - 他的子串的哈希值就是区间和
区间和:
时间复杂度:
例题:
P3370 【模板】字符串哈希
模板题,直接上代码。
#include<bits/stdc++.h> using namespace std; #define ULL unsigned long long const int maxn=100010; const int p=131; int n; int lens; char s[maxn]; ULL ans[maxn],h[maxn]; int cnt=0; ULL calc(char s[],int n) { h[0]=0; for(int i=1;i<=lens;i++) { h[i]=h[i-1]*p+s[i]; //求 hash 值,前缀和,便于求区间 hash 值(虽然这题不需要 QWQ ) } return h[lens]; } //计算哈希值 int main(){ cin>>n; for(int i=1;i<=n;i++) { scanf("%s",s+1); lens=strlen(s+1); ans[i]=calc(s,lens);//计算哈希值 } sort(ans+1,ans+1+n); for(int i=1;i<=n;i++) { if(ans[i]!=ans[i-1])cnt++; } cout<<cnt<<endl; return 0; }
P2957 [USACO09OCT] Barn Echoes G
- 题目大意:求两个字符串s1 s2的重复部分
两个字符串的重复部份指的是同时是一个字符串的前缀和另一个字符串的后缀的字符串
- 思路:
计算hash值,枚举重复部分的长度,计算区间hash值相等的最长长度。
虽然这道题暴力也可以,但是好不容易碰见一道能用hash的题 - 代码:
//30ms直接拿下! #include<bits/stdc++.h> using namespace std; #define ULL unsigned long long const int p=131; char s1[100],s2[100]; ULL h[100][5],pow_p[100]; int ans=0; ULL get_valu(int l,int r,int cnt) //求区间hash值 { return h[r][cnt]-h[l-1][cnt]*pow_p[r-l+1]; } void Hash(char t[],int cnt)//hash函数 { h[0][cnt]=0; int len=strlen(t+1); for(int i=1;i<=len;i++) { h[i][cnt]=h[i-1][cnt]*p+t[i]; } } int main() { scanf("%s%s",s1+1,s2+1); Hash(s1,1);//分别求出hash值 Hash(s2,2); pow_p[0]=1; for(int i=1;i<=100;i++) pow_p[i]=pow_p[i-1]*p;//直接预处理一下p的次方 int len1=strlen(s1+1); int len2=strlen(s2+1); int maxn=min(len1,len2); for(int i=maxn;i>=1;i--) { int nums1_big=get_valu(1,i,1),nums1_ed=get_valu(len1-i+1,len1,1), nums2_big=get_valu(1,i,2),nums2_ed=get_valu(len2-i+1,len2,2); //求长度为 i 的 s1 前缀hash值、后缀hash值 和 s2 的前缀hash值、后缀hash值 // cout<<nums1_big<<" "<<nums1_ed<<" "<<nums2_big<<" "<<nums2_ed<<endl;调试 if(nums1_big==nums2_ed||nums2_big==nums1_ed) { cout<<i<<endl; return 0; } } }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战