哈希表说简单一点就是将一个大的集合映射到一个比较小的集合中

一个很经典的例子 —— 字符串哈希
给定一个长度为 n 的字符串,再给定 m 个询问,每个询问包含四个整数 l_1,r_1,l_2,r_2,请你判断 [l_1,r_1][l_2,r_2] 这两个区间所包含的字符串子串是否完全相同。

当字符串的长度为10^9时,遍历显然就不便利了(谐音虽迟但到)这个时候可以将字符串以一种特殊的方式变成数字编码,每一个数字编码只对应一个字符串

一个具体的例子:如字符串ABCD,其中可以做如下映射:
A->1,B->2,C->3,D->4
继续将字符串看做一个P进制的数,则
ABCD=P^3+2P^2+3P^1+4P^0,这样该P进制数唯一对应ABCD字符串。

加上的前缀哈希的思想,现将前k位的哈希值算出来。
再回到上述问题:从 lr 之间的字符串的哈希值如和得到?
类似于二进制的计算,如11010与110的差,要先将110转换为00110,将二者位数对齐,在进行计算,则我们可以得到以下公式:

具体代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

//字符前缀哈希法   h[k]表示前k个字符的哈希
//将字符串转换为P进制数  如ABCD=(1,2,3,4)p  则其哈希值为(1*p^3+2*p^2+3*p^1+4*1)_10
//在对哈希值取模 mod Q
typedef unsigned long long  ULL;

const int N = 100010, P = 131;        //P取131或13331  经验数值
int n, m;
char str[N];

ULL h[N], p[N];   

ULL getLR(int l, int r)    
{
    return h[r] - h[l - 1] * p[r - l + 1];         //计算l,r之间的哈希值
}

int main()
{
    cin >> n >> m >> str+1;
    p[0] = 1;
    for (int i = 1; i <= N; i++)
        p[i] = p[i - 1] * P,
        h[i] = h[i - 1] * P + str[i];              //计算前i位的哈希值

    while (m--)
    {
        int l1, r1, l2, r2;
        cin >> l1 >> r1 >> l2 >> r2;

        if (getLR(l1, r1) == getLR(l2, r2)) puts("Yes");
        else puts("No");
    }

    return 0;
}
分类: 算法集

0 条评论

发表评论

Avatar placeholder

邮箱地址不会被公开。 必填项已用*标注