使用另一种进制来表示字符串,在该进制表示下的字符串的值即为哈希值。
包含小写字母的字符串,只有26中可能性,可以使用27进制。
自己设定:在26进制下a=1,b=2,c=3..............z=26
那么字符串 "a"的哈希值=1 ,“aa”的哈希值=28。
反之哈希值=1的字符串是 “a”, 哈希值=28 的字符串是“aa”。
哈希值与字符串一一对应。
前 i 个字符的哈希值为hash[i]
第i位的权值为
比如一个字符串 "abaab"
自己设定:27进制表示下,a=1 ,b=2 , c=3 ...........
0 | 1 | 2 | 3 | 4 | 5 | |
字符串 | a | b | a | a | b | |
hash: | 0 | 0*27+1=1 | 1*27+2=29 | 29*27+1=784 | 784*27+1=21142 | 21142*27+2=570836 |
value: | 1 | ![]() |
![]() |
![]() |
![]() |
![]() |
通过计算得以上的hash之后,就可以求出任意子串的hash了。
比如求子串 [2,3] - “ba” 的哈希值, 哈希值 = hash[3] -hash[1]*value[3-1] =784-1*=55 (验证:"ba"在27进制下表示为
=2*27+1=55 )
hash[3]表示前3个字符的哈希值。
hash[1]表示前1个字符的哈希值
hash[1]*value[3-1]就是直接从i=1到达i=3而不加上第2,3位的值,所以 hash[3] 和 hash[1]*value[3-1] 差值就是未被加上的子串[2,3]的哈希值.
所以求子串 [ l , r ] 哈希值即是:hash[r] - hash[l-1] * value[r-l+1]
#include
using namespace std;
typedef unsigned long long ull;
void GetHash(string& s,ull hash[],ull value[]){
const int MOD=27;
value[0]=1;
hash[0]=0;
for(int i=0;i>s;
GetHash(s,hash,value);
cout<
注意:
代码中使用里unsigned long long 类型,可以实现一些效果:
计算出来的哈希值往往过大,unsigned long long 是定点类型里范围最大的,而且溢出是可以自动对取模。
第二个作用:hash[r] - hash[l-1] * value[r-l+1] , 由于在取模意义下做减法可能会出现负数,unsigned long long 是无符号类型,负数即是负溢出,负溢出时同样自动对取模。