定义
我们定义一个把字符串映射到整数的函数f,这个 f 称为是 Hash 函数,我们希望这个函数 f 可以方便地帮我们判断两个字符串是否相等
中心思想
将输入映射到一个值域较小,可以方便比较的范围,一般是将字符串视为一个p进制数去进行Hash值的计算
重要性质
在 Hash 函数值不一样的时候,两个字符串一定不一样;
在 Hash 函数值一样的时候,两个字符串不一定一样(但有大概率一样,且我们当然希望它们总是一样的)
我们将 Hash 函数值一样但原字符串不一样的现象称为哈希碰撞
为了避免这种情况,一般将进制p设为131或13331这两个质数
代码实现
//计算一段的Hash值
unsigned long long get( int a,int b )
{
return h[b] - h[a] * power[b-a+1];
//将前b个的Hash减去前a个的Hash,因为对于h[a],在h[b]中它的值是h[a]的p^(b-a+1)倍(每次计算Hash时会对其前缀额外乘p),所以要对h[a]乘上power[b-a+1]
}
//构建Hash数组
power[0]=1;//存储幂次方的数组
int len=strlen( A+1 );
for( int i=1;i<=len;i++ )
{
h[i]=h[i-1]*p+A[i];//即进制转换的思想
power[i]=power[i-1]*p;
}
//超快速的比对
for( int i=1;i<=m;i++ )
{
int l1, r1, l2, r2;
scanf( "%d%d%d%d",&l1 , &r1, &l2, &r2 );//需要比对的两个区间
if( get( l1,r1 ) == get( l2,r2 ) ) //一般会封装一个get函数去获得对应段的Hash值
{
printf( "Same" );
}
else
{
printf( "Different" );
}
}
时间复杂度
O(1)
小技巧
(1):
对于回文串的判断
可以在每两个字符之间插入一个不会影响题目的字符并在两端再加入此字符,就可以保证修改后长度为奇数
就可以使用中点扩散法了
(2):
存储hash值时,难免会有数据大小溢出的情况产生,此时需要我们重复mod一个值
又因为在C++中电脑计算mod运算的速度很慢
所以我们可以使用64位无符号长整型unsigned long long存储hash值
这样在hash值超过ull上限时会直接归零,相当于不断地mod -1上
可以有效且便捷的提速