字符串哈希
Keywords: #algorithm
字符串哈希,是一种能将字符串映射成非负整数的算法.
一般使用BKDR Hash进行哈希计算.
具体做法是,将字符串看作一个 $b$ 进制的数字,计算它在十进制下的数值.
由于在字符串足够长时数字会过大,因此一般会取模一个大质数.
参考代码(只包含a-z的字符串):
const int mod=1e9+7,b=27;
int getstrhash(string str){
int len=str.size();
int ans=0;
for(int i=0;i<len;i++){
ans=((long long)ans*b+(str[i]-'a'+1))%mod;
}
return ans;
}
注意:如果使用上面的做法,注意是
str[i]-'a'+1
,否则aab
和ab
的哈希值相同.
上面这种方法因为在实际使用时涉及到大量取模操作,所以通常利用unsigned long long
类型溢出自动取模 $2^{64}-1$的性质,使用下面这种方法:
const int b=27;
unsigned long long getstrhash(string str){
int len=str.size();
unsigned long long ans=0;
for(int i=0;i<len;i++){
ans=ans*b+(str[i]-'a'+1);
}
return ans;
}
求子串哈希
如果要计算子串哈希(比较子串是否相等),直接暴力计算,单次查询 $O(n)$ 复杂度.
使用类似前缀和的思想可以优化此过程.
具体做法是,预处理字符串(假设为str)的每个前缀哈希,利用求哈希时将字符串看作一个 $b$ 进制数的特点,将哈希值"左移"后相减.
例子:给定字符串 $s=“abb”$,求 $“bb”$ 的哈希值.
预处理出前缀哈希值
$pre[0]=1*27^0=1$
$pre[1]=1*27^1+2*27^0=29$
$pre[2]=1*27^2+2*27^1+2*27^0=785 $
然后结果为$pre[2]-pre[0]*27^2$.
参考代码
int getsubstrhash(int l,int r){
return pre[r]-pre[l-1]*powofbase[r-l+1];
//powofbase[i]为b的i次方
}