其他分享
首页 > 其他分享> > 字符串哈希(快速求取 某段字符串的值):

字符串哈希(快速求取 某段字符串的值):

作者:互联网

题目链接:https://www.acwing.com/problem/content/843/

题目:

给定一个长度为 n 的字符串,再给定 m 个询问,每个询问包含四个整数 l1,r1,l2,r2。请你判断 [l1,r1] 和 [l2,r2] 这两个区间所包含的字符串子串是否完全相同。

字符串中只包含大小写英文字母和数字。

输入格式

第一行包含整数 n 和 m,表示字符串长度和询问次数。

第二行包含一个长度为 n 的字符串,字符串中只包含大小写英文字母和数字。

接下来 m 行,每行包含四个整数 l1,r1,l2,r2,表示一次询问所涉及的两个区间。

注意,字符串的位置从 1 开始编号。

输出格式

对于每个询问输出一个结果,如果两个字符串子串完全相同则输出 Yes,否则输出 No

每个结果占一行。

数据范围

1≤n,m≤1e5

输入样例:

8 3
aabbaabb
1 3 5 7
1 3 6 8
1 2 1 2

输出样例:

Yes
No
Yes

使用场景:

主要用于多次询问某两段字符串是否相同。如果相同其字符串哈希值是相同的,如果不同其字符串哈希值则不同。

结论:

字符串哈希中,取131,1331,13331...(已经经过了他人证明)作为进制值,而取模则取2 ^ 64时,  此时冲突发生的几率极小。 

为什么y取 2 ^ 64?

如果x(x进制的意思)大于你字符串的字符集,则不会出现冲突,但是比如以所有的中文字作为字符集,大概1w+以上,则x至少为1w+以上的值。

而字符串对应的值则是 x ^ n + x ^ (n-1) + x ^ (n - 2) + .... + x ^ 0 很容易就爆了c++最大存储值。

所以就需要进行取模运算, % y,    而 %y的话 ,就说明有可能会发生冲突。而y越大,发生冲突的概率越小,所以y取 2 ^ 64最好。  而 % (2 ^ 64)实际上就是 unsigned long long 发生上溢的情况。

 注意:

字符集中要确保 每一个字符所对应的进制值不为0.

比如:0,00,000,它的哈希值是相同的,但是它们不是同一个字符串。

 代码实现:

# include <iostream>
using namespace std;

const int N = 1e5 + 10 , P = 131;

int n,m;

unsigned long long h[N],p[N];

unsigned long long get(int l1,int r1)
{
    return h[r1] - h[l1 - 1] * p[r1 - l1 + 1];
}

int main()
{
    scanf("%d %d",&n,&m);
    p[0] = 1;
    for(int i = 1 ; i <= n ; i++)
    {
        char temp;
        cin >> temp;
        p[i] = p[i - 1] * P;
        h[i] = h[i - 1] * P + temp;
    }
    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;
}

标签:r1,r2,某段,int,l2,哈希,l1,字符串
来源: https://blog.csdn.net/qq_49120553/article/details/118658155