字符串串基础——字符串Hash,KMP,Trie树
作者:互联网
终于来到了我最不想学的字符串
字符串Hash
原理
把字符串看做 \(b\) 进制数,把字符串 \(S\) 映射成一个函数 \(hash(S)\) ,即一个数字,便于比较
$ hash(S) = (S_1b^{n-1}+ S_2b^{n-2}+\dots+S_n)\pmod p $
计算 \(hash\) 函数的时间复杂度是 \(O(\mid S\mid)\) ,这里一般选 \(233\) 作为进制, \(10^9+7\) , \(10^9+9\) ,\(10^9+21\) 作为模数
如果在处理字符串子串 \(hash\) 值的时候再计算时间复杂度就会飙升到 \(O(n^2)\)
所以我们可以将字符串的前缀 \(hash\) 预处理出来,用时 \(O(1)\) 查询即可(原理为把高位消掉)
例题
乌力波
题意:给定两个串 \(W,T\) 求 \(W\) 在 \(T\) 中出现的次数
模板题
点击查看代码
#include<bits/stdc++.h>
#define N 1000005
#define b 233
#define mod 1000000021
#define ll long long
using namespace std;
int q;
ll hashw,hashs[N],p[N];
inline string getstr();
ll gethash(int l,int r);
int main(){
cin>>q;
p[0]=1;
for(int i=1;i<=N-2;i++)
p[i]=p[i-1]*b%mod;
while(q--){
int ans=0;
string w,t;
w=getstr();t=getstr();
int wlen=w.size(),tlen=t.size();
hashw=0;
for(int i=0;i<wlen;i++)
hashw=(hashw*b+w[i])%mod;
hashs[0]=t[0];
for(int i=1;i<tlen;i++)
hashs[i]=(hashs[i-1]*b+t[i])%mod;
for(int i=0;i+wlen-1<tlen;i++)
if(hashw==gethash(i,i+wlen-1))
ans++;
printf("%d\n",ans);
}
}
inline string getstr(){
char ch=getchar();
string s="";
while(ch==' '||ch=='\n')
ch=getchar();
while(ch!=' '&&ch!='\n')
s+=ch,ch=getchar();
return s;
}
ll gethash(int l,int r){
return (hashs[r]-hashs[l-1]*p[r-l+1]%mod+mod)%mod;
}
P3667 [USACO17OPEN]Bovine Genomics G
二分+ \(hash\)
枚举左端点,然后对于长度二分答案,先把 \(B\) 串的 \(hash\) 值先排个序,然后对于 \(A\) 串的每个 \(hash\) 值,二分查找然后判断是否相等即可
还需要注意的一点是这道题答案的单调性有所不同,对于有解的情况有最小值而不是最大值
点击查看代码
#include<bits/stdc++.h>
#define N 505
#define B 233
#define ll long long
using namespace std;
const ll mod=1e9+21;
int n,m,ans=N+100;
ll p[N],hash_suma[N][N],hash_sumb[N][N];
string a[N],b[N];
inline string getstr();
inline ll gethasha(int i,int l,int r);
inline ll gethashb(int i,int l,int r);
int main(){
// freopen("P3667_2.in","r",stdin);
cin>>n>>m;
p[0]=1;
for(int i=1;i<=N-2;i++)
p[i]=p[i-1]*B%mod;
for(int i=1;i<=n;i++)
a[i]=getstr();
for(int i=1;i<=n;i++)
b[i]=getstr();
for(int i=1;i<=n;i++){
hash_suma[i][0]=a[i][0];
hash_sumb[i][0]=b[i][0];
for(int j=1;j<m;j++){
hash_suma[i][j]=(hash_suma[i][j-1]*B+a[i][j])%mod;
hash_sumb[i][j]=(hash_sumb[i][j-1]*B+b[i][j])%mod;
}
}
for(int i=0;i<m;i++){
int l=1,r=m-i;
int t=605;
while(l<=r){
int mid=(l+r)>>1;
int j=i+mid-1;
bool flag=false;
ll tmp[n+5];
for(int k=1;k<=n;k++)
tmp[k]=gethashb(k,i,j);
sort(tmp+1,tmp+n+1);
for(int k=1;k<=n;k++){
int temp=lower_bound(tmp+1,tmp+1+n,gethasha(k,i,j))-tmp;
if(tmp[temp]==gethasha(k,i,j)){
flag=true;
break;
}
}
if(flag) l=mid+1;
else{
t=min(t,mid);
r=mid-1;
}
}
if(t) ans=min(ans,t);
}
cout<<ans;
}
inline string getstr(){
char ch=getchar();
string s="";
while(ch==' '||ch=='\n')
ch=getchar();
while(ch!=' '&&ch!='\n')
s+=ch,ch=getchar();
return s;
}
inline ll gethasha(int i,int l,int r){
return (hash_suma[i][r]-hash_suma[i][l-1]*p[r-l+1]%mod+mod)%mod;
}
inline ll gethashb(int i,int l,int r){
return (hash_sumb[i][r]-hash_sumb[i][l-1]*p[r-l+1]%mod+mod)%mod;
}
标签:Hash,Trie,ll,long,int,字符串,hash,define 来源: https://www.cnblogs.com/Rolling-star/p/16512869.html