哈希字符串复习

哈希字符串复习

前话:这里复习一波哈希字符串,因为忘了,就是这么简单。

方法1:自然溢出法。

利用 u n s i g n e d   l o n g   l o n g unsigned\ long\ long 超出 2 64 1 2^{64}-1 会自动对其取模的特性,我们考虑用 [ 0 , 2 64 1 ) [0,2^{64}-1) 的范围的数表示一个字符串,类比二进制,我们用一个素数 p p 定义一个 p p 进制。

有: h a s h [ i ] = h a s h [ i 1 ] × p + i d x ( s t r [ i ] ) hash[i]=hash[i-1]\times p+idx(str[i])

i d x ( ) = s t r [ i ] a + 1 idx()=str[i]-'a'+1 ,或者直接用其 A S C I I ASCII 码。

优点:常数小,时间快。

缺点:出现哈希冲突的可能性较大,错误率较大。

方法2:单值 h a s h hash

考虑:用一个素数代替自然溢出法实现取模。

即: h a s h [ i ] = [ h a s [ i 1 ] × p + i d x ( s t r [ i ] ) ] % m o d hash[i]=[has[i-1]\times p+idx(str[i])]\%mod

这里给出子串 s [ l r ] s[l\dots r] h a s h hash 值:

h a s h l r = ( ( h a s h [ r ] h a s h [ l 1 ] × p r l + 1 % m o d ) + m o d ) % m o d hash_{l\dots r}=((hash[r]-hash[l-1]\times p^{r-l+1}\%mod)+mod)\%mod

相较自然溢出法,错误率更低。不过出题人可能会卡掉叫常见的素数,所以取素数建议取较大且不常见的素数。

方法3:双值 h a s h hash

考虑:两个 h a s h hash 来唯一确定一个字符串,即一个 h a s h hash < h a s h 1 , h a s h 2 > <hash_1,hash_2>

h a s h 1 [ i ] = ( h a s h 1 [ i 1 ] × p + i d x ( s [ i ] ) ) % m o d 1 h a s h 2 [ i ] = ( h a s h 2 [ i 1 ] × p + i d x ( s [ i ] ) ) % m o d 2 hash_1[i]=(hash_1[i-1]\times p+idx(s[i]))\%mod_1\\hash_2[i]=(hash_2[i-1]\times p+idx(s[i]))\%mod_2

实现方法的代码:

1.自然溢出法.

#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#define ull unsigned long long
using namespace std;
const int N=1e5+5;
char s[N];
ull h[N],p[N];
int base=2333;
int main(){
	scanf("%s",s+1);
	int n=strlen(s+1);
	p[0]=1;
	for(int i=1;i<=n;i++)
		p[i]=p[i-1]*base,h[i]=h[i-1]*base+(s[i]-'a'+1);
	for(int i=1;i<=n;i++)
		printf("h[%d]=%llu\n",i,h[i]);
	int l,r;
	while(cin>>l>>r){
		ull val=h[r]-h[l-1]*p[r-l+1];
		printf("h[%d-%d]=%llu\n",l,r,val);
	} 
} 

在这里插入图片描述

2.单值 h a s h hash .

#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#define ull unsigned long long
using namespace std;
const int N=1e5+5;
char s[N];
ull h[N],p[N],mod=998244353;
int base=2333;
int main(){
	scanf("%s",s+1);
	int n=strlen(s+1);
	p[0]=1;
	for(int i=1;i<=n;i++)
		p[i]=p[i-1]*base%mod,h[i]=(h[i-1]*base+(s[i]-'a'+1))%mod;
	int l,r;
	while(cin>>l>>r){
		ull val=(h[r]-h[l-1]*p[r-l+1]%mod+mod)%mod;
		printf("h[%d-%d]=%llu\n",l,r,val);
	} 
} 

3.双值 h a s h hash .

#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#define ull unsigned long long
using namespace std;
const int N=1e5+5;
char s[N];
int n;
ull h1[N],h2[N],p1[N],p2[N],mod1=1e9+7,mod2=1e9+9;
ull base=2333;
void Get_Hash(ull *h,ull *p,ull mod){
	p[0]=1;
	for(int i=1;i<=n;i++)
		p[i]=p[i-1]*base%mod,h[i]=(h[i-1]*base+(s[i]-'a'+1))%mod;
}
int main(){
	scanf("%s",s+1);
	n=strlen(s+1);
	Get_Hash(h1,p1,mod1);
	Get_Hash(h2,p2,mod2);
	int l,r;
	while(cin>>l>>r){
		ull val1=(h1[r]-h1[l-1]*p1[r-l+1]%mod1+mod1)%mod1;
		ull val2=(h2[r]-h2[l-1]*p2[r-l+1]%mod2+mod2)%mod2;
		printf("h1=%llu,h2=%llu\n",val1,val2);
	} 
} 

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45750972/article/details/107447035
今日推荐