字符串哈希算法
字符串哈希顾名思义哈希,可以理解成将字符串映射为一个特定的数字,并且字符串不同,得到的哈希值也不同,那么就可以判断两个字符串是否相等。
用于:快速判断两个字符串(子字符串)是否相等,时间复杂度为O(1)。
核心:把字符串看成一个P进制的数,算出该字符串对应的P进制数。
用unsigned long long来记录字符串前缀的P进制哈希值,并且可以自动处理数字溢出(相当于自动对2^64−1取模)。
算法:用hash[]数组,记录给定字符串从1~n位前缀的P进制哈希值,公式为:hash[i]=hash[i-1]*P+str[i]
比如当前字符串是“abcac”,hash[1]表示“a”的P进制哈希值,hash[2]表示“ab”的P进制哈希值,hash[3]表示“abc”的P进制哈希值......那么如何计算“abc”的P进制哈希值?其实如图十进制数一样,如123=1*10^2+2^10^1+3*10^0,“abc”的P进制哈希值=hash[3]='a'*P^2+'b'*P^1+'c'*P^0,其中每一位字母对应其ASCII值,P根据经验通常取131,1331,13331,如此便可以计算出字符串任一前缀的P进制哈希值,记录在hash[]数组中。
那么当计算对应区间为[l,r]上子字符串的哈希值,我们只需要知道hash[l-1] 和 h[r]即可求得[l,r]区间的哈希值。将hash[l-1]:(l-1)位hash值通过移位操作成r位,再与h[r]进行相减操作,即可得到[l,r]区间上的hash值。拿十进制举例:12345,求2~4位的哈希值,即l=2,r=4,hash=1234-1*10^3=234。
公式为:Hash[L, R]=(Hash[R]−Hash[L−1]×P ^{R−L+1} )
相应题目及代码:



代码:
#include<iostream> using namespace std; typedef unsigned long long ull; const int P=131; int main(){ int n,m; scanf("%d",&n); scanf("%d",&m); char *str=new char[n+1]; ull *hash=new ull[n+1];//下标从1开始,hash[i]表示str前缀1~i的哈希值 ull *p=new ull[n+1];//p[i]表示P的i次方 cin>>str; p[0]=1; for(int i=1;i<=n;i++){ hash[i]=hash[i-1]*P+str[i-1]; p[i]=p[i-1]*P; } while(m--){ int s1,s2,e1,e2; cin>>s1>>e1>>s2>>e2; if((hash[e1]-hash[s1-1]*p[e1-s1+1])==(hash[e2]-hash[s2-1]*p[e2-s2+1]))cout<<"Yes"<<endl; else cout<<"No"<<endl; } return 0; }

浙公网安备 33010602011771号