字符串哈希算法

字符串哈希顾名思义哈希,可以理解成将字符串映射为一个特定的数字,并且字符串不同,得到的哈希值也不同,那么就可以判断两个字符串是否相等。

用于:快速判断两个字符串(子字符串)是否相等,时间复杂度为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;
}

 

posted @ 2022-07-28 18:03  blazerrr  阅读(895)  评论(0)    收藏  举报