其他分享
首页 > 其他分享> > 字符串哈希模板

字符串哈希模板

作者:互联网

模板题:https://www.acwing.com/problem/content/843/

字符串前缀哈希法,把字符串变成一个p进制数字(哈希值),实现不同的字符串映射到不同的数字。
对形如 X 1 X 2 X 3 ⋯ X n − 1 X n X_1X_2X_3⋯X_{n−1}X_n X1​X2​X3​⋯Xn−1​Xn​ 的字符串,采用字符的 A S C I I ASCII ASCII 码乘上 P P P 的次方来计算哈希值。

映射公式 ( X 1 × P n − 1 + X 2 × P n − 2 + ⋯ + X n − 1 × P 1 + X n × P 0 )   m o d   Q (X_1×P_{n−1}+X_2×P_{n−2}+⋯+X_{n−1}×P_1+X_n×P_0)\ mod\ Q (X1​×Pn−1​+X2​×Pn−2​+⋯+Xn−1​×P1​+Xn​×P0​) mod Q

注意:

  1. 任意字符不可以映射成 0 0 0,否则会出现不同的字符串都映射成 0 0 0 的情况,比如 A A A, A A AA AA, A A A AAA AAA皆为 0 0 0
  2. 冲突问题:通过巧妙设置 P P P ( 131 131 131 或 13331 13331 13331) , Q Q Q ( 2 64 2^{64} 264)的值,一般可以理解为不产生冲突。

问题是比较不同区间的子串是否相同,就转化为对应的哈希值是否相同。
求一个字符串的哈希值就相当于求前缀和,求一个字符串的子串哈希值就相当于求部分和。

前缀和公式
h [ i + 1 ] = h [ i ] × P + s [ i ] i ∈ [ 0 , n − 1 ] h[i+1]=h[i]×P+s[i] \qquad i∈[0,n−1] h[i+1]=h[i]×P+s[i]i∈[0,n−1]
h h h 为前缀和数组, s s s 为字符串数组
区间和公式
h [ l , r ] = h [ r ] − h [ l − 1 ] × P r − l + 1 h[l,r]=h[r]−h[l−1]×P_{r−l+1} h[l,r]=h[r]−h[l−1]×Pr−l+1​
区间和公式的理解:
ABCDE 与 ABC 的前三个字符值是一样,只差两位,
乘上 P 2 P_2 P2​ 把 ABC 变为 ABC00,再用 ABCDE - ABC00 得到 DE 的哈希值。
h [ r ] − h [ l − 1 ] h[r] - h[l-1] h[r]−h[l−1] 这里 h [ r ] h[r] h[r] 的最高位是 P r − 1 P^{r-1} Pr−1 , h [ l − 1 ] h[l-1] h[l−1] 的最高位是 P l − 2 P^{l-2} Pl−2 要对齐来作差就要乘上 P r − l + 1 P^{r-l+1} Pr−l+1

#include <cstdio>

using namespace std;

const int N = 100010,P = 131;

// 用unsigned long long 刚好是2的64次,溢出相当于取模
typedef unsigned long long ULL;

int n,m;
char str[N];
ULL h[N],p[N];
// h[i]前i个字符的hash值
// 字符串变成一个p进制数字,体现了字符+顺序,需要确保不同的字符串对应不同的数字
// P = 131 或  13331 Q=2^64,在99%的情况下不会出现冲突
// 使用场景: 两个字符串的子串是否相同

ULL get(int l,int r)
{
    return h[r] - h[l - 1] * p[r - l + 1];
}

int main()
{
    scanf("%d%d",&n,&m);
    scanf("%s",str+1);
    p[0] = 1;
    for(int i = 1; i <= n; i++)
    {
        h[i] = h[i-1] * P + str[i]; // 前缀和求整个字符串的哈希值
        p[i] = p[i-1] * P;
    }
    while(m--)
    {
        int l1,r1,l2,r2;
        scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
        
        if(get(l1,r1) == get(l2,r2)) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

标签:前缀,int,d%,131,哈希,字符串,模板
来源: https://blog.csdn.net/m0_51560548/article/details/120969920