其他分享
首页 > 其他分享> > 字符串串基础——字符串Hash,KMP,Trie树

字符串串基础——字符串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