以下内容来源https://blog.csdn.net/Coldfresh/article/details/79476915, 作者Coldfresh
字符串hash是指将一个字符串s映射为一个,使得该整数可以尽可能唯一的代表也就是唯一标识。换言之,如果两个字符的hash值相同那么我们可以认为两者相同。
这里使用的hash策略,便是把一个字符串的每一位赋予权值
假设都是大写的英文字母。
我们设
H[i]代表前i个hash值
那么
H[i]=H[i−1]∗p+val[i]
这里因为是大写英文字母,只有26 中不同的表示,所以这里可以设p为26。(实际上就是把26进制数用10进制数表示)
接下的问题是如果字符串的位数很长,那么很可能所产生的hash值会超过技术表示的范围(以int和long类型为例)。
所以我们可以设置一个数mod,即去余
H[i]=(H[i−1]∗p+val[i])%mod
那么这样可以解决数字太大的问题,但是会造成的另一个问题是产生碰撞,即不同的字符串的hash值可能会相同。
根据相关资料,如果我们把p设置为一个10^7(如10000019)大小,把mod设为一个10^9(如1000000009)大小的数,那么发生碰撞的概率就非常低。
后来我问斌爷,斌爷说把p设为233就够啦,基本上碰撞的概率极小233。
一个延伸问题:如果我得到了一个字符串的hash值,那么怎么得到其中任意一个子串的hash?
首先易知:
H[i...j]=val[i]∗p^(j−i)+val[i+1]∗p^(j−i−1)+val[i+2]∗p^(j−i−2)+...+val[j]∗p^0
显然:
H[j]=H[i−1]∗p^(j−i+1)+H[i...j]
所以:
H[i...j]=(H[j]−H[i−1]∗p^(j−i+1))
这个时候去模:
H[i...j]=((H[j]−H[i−1]∗p^(j−i+1))%mod+mod)%mod
完毕。
以上为转载内容。
如果仍怕冲突,可以开不同种子的Hash表共同判断。
const int maxn = 10005; int n; char s[maxn]; struct Hash { int p,P,hash1[maxn],hash2[maxn];//hash1[i]是上文的H[i],hash2[i]是上文的p^i void init(int p1,int P1) { p=p1,P=P1; hash2[0]=1; for(int i=1; i<=n; i++) { hash1[i]=(1LL*hash1[i-1]*p+(s[i]-'a'+1))%P; hash2[i]=1LL*hash2[i-1]*p%P; } } int getha(int L,int R) { return (hash1[R]-1LL*hash1[L-1]*hash2[R-L+1]%P+P)%P; } };
例题:
好文章:
Description
nodgd写了一篇文章,自认为这是一篇好文章。nodgd的文章由n个小文字母组成。文章的一个子串指的是文章中的一段连续的字母,子串的长度这一段的字母个数。nodgd在文章中用了排比、对偶、前后照应之类的手法以就有很多个子串是相同或者相近的。为了向大家证明这是一篇好文章,决定给自己的文章进行评分。nodgd 首先确定了一个整数m,然后统计出文有多少个不相同的长度为m的子串,这个数量就是文章的评分。
然而,nodgd懒得老老实实计算这个评分了,就把任务丢给了你。
Input
第一行包含两个整数n,m,表示文章的长度和需要统计的子串长度。 第二行包含一个长度为n的只包含小写字母的字符串。
Output
输出一行一个整数,表示文章的评分。
Sample Input 1
【样例1】 5 3 aaaab 【样例2】 9 3 abcabacba
Sample Output 1
【样例1】 2
【样例2】 7
Hint
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int maxn=5e5+5, mod1=1e9+7, mod2=1e9+9; int n,m; char s[maxn]; //哈希表 struct Hash { int p,P,hash1[maxn],hash2[maxn]; void init(int p1,int P1) { p=p1,P=P1; hash2[0]=1; for(int i=1; i<=n; i++) { hash1[i]=(1LL*hash1[i-1]*p+(s[i]-'a'+1))%P; hash2[i]=1LL*hash2[i-1]*p%P; } } int getha(int L,int R) { return (hash1[R]-1LL*hash1[L-1]*hash2[R-L+1]%P+P)%P; } } Ha,Hb; struct Charactor { int h1,h2; bool operator<(const Charactor& h)const { return h1==h.h1?h2<h.h2:h1<h.h1; } } H[maxn]; int main() { int i,j,ans=1; scanf("%d%d", &n, &m); scanf("%s", s+1); Ha.init(47, mod1);//不同种子 Hb.init(91, mod2); for(i=1; i+m-1<=n; i++) { H[i].h1=Ha.getha(i,i+m-1); H[i].h2=Hb.getha(i,i+m-1); } sort(H+1,H+1+n-m+1); for(i=2; i+m-1<=n; i++) ans+=(H[i].h1!=H[i-1].h1||H[i].h2!=H[i-1].h2);//两个哈希中有一个不等即可 cout<<ans; }