字符串哈希(快速求取 某段字符串的值):
作者:互联网
题目链接: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