字符串哈希
Posted zjy0217
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符串哈希相关的知识,希望对你有一定的参考价值。
字符串哈希
将一串字符串映射为一个唯一对应的整数,将字符串的比较(O(n))化简为(O(1))
哈希:将一个字符串看作一个p进制数再模上q
abcabcdefg
1.2.3.1.2.3.4.5.6.7.
=(1*p^9+2*p^8+3*p^7+1*p^6+2*p^5+3*p^4+4*p^3+5*p^2+6*p^1+7*p^0)%q
=hash值(属于0~q-1)
当p取131、13331 q取2^64 (unsigned long long)时重复率最小
abd
(1.2.3)131
=1*131^2+2*131^1+4*131^0
=hash(‘abd‘)
会溢出int 但是若命做ULL 相当于自动取模2^64
一般在使用中我们会存下前缀值
要求hash(‘abcde‘)
会先存下 h[0]=0
hash(‘a‘)
hash(‘ab‘)
hash(‘abc‘)
hash(‘abcd‘)=hash(‘abc‘)*131+4
所以hash(i)与hash(i+1)之间存在一个递推式hash(i+1)=hash(i)*131+strlen(i+1)
若要求
L R
。。。。。。。。。。
h(L-R)=h(R)-h(L-1)*131^(R-L+1)
这里令131^(R-L+1)=p[R-L+1]
//板子
const int maxn=1e6+5,base=131;
char s[maxn];
ULL h[maxn],p[maxn];
ULL gethash(int l,int t)
{
return h[r]-h[l-1]*p[r-l+1];
}
void init()
{
p[0]=1;
for(int i=1;i<=maxn;i++)
p[i]=p[i-1]*base;
}
int main ()
{
init();
scanf("%s",s+1);
int len=strlen(s+1);
h[0]=0;
for(int i=1;i<=len;i++)
h[i]=h[i-1]*base+str[i]-‘a‘+1;
cin>>…………………………
}
例1 https://vjudge.net/problem/HDU-1686
Oulipo
#include<iostream>
#include<cstring>
using namespace std;
typedef unsigned long long ULL;
const int maxn=1e4+5,base=131;
char str1[maxn],str2[1000005];
ULL h[1000005],p[1000005],str;
int n1,n2,cnt;
ULL gethash(int l, int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
void init()
{
p[0]=1;
for(int i=1;i<=1000005-1;i++)
p[i]=p[i-1]*base;
}
int main()
{
init();
int n;
cin>>n;
while(n--)
{
h[0]=0;str=0;cnt=0;
scanf("%s",str1+1);
//getchar();
scanf("%s",str2+1);
n1=strlen(str1+1);n2=strlen(str2+1);
for(int i=1;i<=n1;i++)
str=str*base+(ULL)str1[i];
for(int i=1;i<=n2;i++)
h[i]=h[i-1]*base+(ULL)str2[i];
for(int i=1;i<=n2-n1+1;i++)
if (str==gethash(i,i+n1-1)) cnt++;
cout<<cnt<<endl;
}
return 0;
}
例二 https://vjudge.net/problem/POJ-2406
Power Strings
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef unsigned long long ULL;
const int maxn=1e6+5,base=131;
int cnt,flag;
char s[maxn];
ULL h[maxn],p[maxn];
void init()
{
p[0]=1;
for(int i=1;i<maxn;i++)p[i]=p[i-1]*base;
}
int main ()
{
init();
while(scanf("%s",s+1))
{
int len=strlen(s+1);
if(s[1]==‘.‘&&len==1)break;
cnt=0;h[0]=0;
for(int i=1;i<=len;i++)
h[i]=h[i-1]*base+s[i];
for(int i=1;i<=len;i++)
{
if(len%i!=0)continue;flag=1;
for(int j=i;j<=len;j+=i)
{
if(h[j]-h[j-i]*p[i]!=(ULL)h[i])
{flag=0;break;}
}
if(flag!=0){cnt=i;break;}
}
cout<<len/cnt<<endl;
}
return 0;
}
例三 https://vjudge.net/problem/HDU-4821
String
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
typedef unsigned long long int ULL;
const int maxn=1e5+5,base=131;
int m,l,len,ans;
char s[maxn];
ULL h[maxn],p[maxn];
map<ULL,int>mm;
ULL gethash(int l,int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
void init()
{
p[0]=1;
for(int i=1;i<maxn;i++)p[i]=p[i-1]*base;
}
int main()
{
init();
while(scanf("%d%d",&m,&l)!=EOF)
{
cin>>s+1;
len=strlen(s+1);h[0]=0;ans=0;
for(int i=1;i<=len;i++)
h[i]=h[i-1]*base+s[i]-‘a‘+1;
for(int i=1;i<=l&&i+m*l-1<=len;i++)
{
mm.clear();
for(int j=i;j<i+m*l;j+=l)
mm[(ULL)gethash(j,j+l-1)]++;
if(mm.size()==m)ans++;
for(int j=i+m*l;j+l-1<=len;j+=l)
{
mm[(ULL)gethash(j,j+l-1)]++;
mm[(ULL)gethash(j-m*l,j-m*l+l-1)]--;
if(mm[(ULL)gethash(j-m*l,j-m*l+l-1)]==0)mm.erase((ULL)gethash(j-m*l,j-m*l+l-1));
if(mm.size()==m)ans++;
}
}
cout<<ans<<endl;
}
return 0;
}
以上是关于字符串哈希的主要内容,如果未能解决你的问题,请参考以下文章