字符串哈希是一种将字符串映射为整数的算法。哈希函数将字符串映射到一个固定大小的整数,这个整数通常称为哈希值或哈希码。哈希函数应具有以下特征:
-
一致性:相同的字符串应该总是映射到相同的哈希值上。
-
散列性:不同的字符串应该映射到不同的哈希值上。
-
高效性:计算哈希值的算法应该是高效的。
今天我们用哈希来求一下字符串匹配的问题
先看问题
给定一个长度为 nn 的字符串,再给定 mm 个询问,每个询问包含四个整数 l1,r1,l2,r2l1,r1,l2,r2,请你判断 [l1,r1][l1,r1] 和 [l2,r2][l2,r2] 这两个区间所包含的字符串子串是否完全相同。
字符串中只包含大小写英文字母和数字。
输入格式
第一行包含整数 n 和 m,表示字符串长度和询问次数。
第二行包含一个长度为 n 的字符串,字符串中只包含大小写英文字母和数字。
接下来 m 行,每行包含四个整数 l1,r1,l2,r2,表示一次询问所涉及的两个区间。
注意,字符串的位置从 11 开始编号。
输出格式
对于每个询问输出一个结果,如果两个字符串子串完全相同则输出 Yes,否则输出 No。
每个结果占一行。
数据范围
1≤n,m≤10^5
方法一:
遇到字符串匹配的方式,通常我们要想到KMP算法,个人认为KMP算法比较适合两个字符串来匹配,如果是一个字符串的话,就比较麻烦
方法二:
字符串哈希:
那什么是字符串哈希呢?
我们想要求一个字符串中的两段是不是相等,我们可以把该字符串的每一段都变为一个特殊的数字,然后直接匹配就行,预处理之后匹配的时间复杂度就是o(1)的,那我们现在讲一下如何预处理
之前我们将字符串的每一段都变为一个特殊的数字是怎么意思呢?怎么变呢?
1、我们让字符串的第一个字符乘以一个特殊的数字,然后再加上本身的值,再让前面两个字符乘以特殊的数字的平方,再加上前面两个本身的数值
2、为什么要这样的,因为我们在用哈希的时候,就是相当于把某一个数映射在另外一个区间上,为了最大限度避免冲突,所以要乘以一个特殊数字,那这个特殊数字既可以是131,也可以是13331(这是经验所得,就不证明了)
具体代码如下
#include<iostream>
using namespace std;
typedef unsigned long long ULL;
const int N=100010,P=131;//注意这里是大p,也可以是13331这个值
int n,m;
char str[N];
ULL h[N],p[N];//这里是小p,h[N]代表的是数值,p[N]代表的是存储p的多少次方
ULL get(int l,int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
int main()
{
scanf("%d%d%s",&n,&m,str+1);//str+1代表数组从下标是1开始存储
p[0]=1;
for(int i=1;i<=n;i++)
{
p[i]=p[i-1]*P;//前面是小p,后面是大p,下面也是一样
h[i]=h[i-1]*P+str[i];
}
while(m--)
{
int l1,r1,l2,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
if(get(l1,r1)==get(l2,r2)) puts("Yes");
else puts("No");
}
return 0;
}
最后欢迎大家来到acwing学习算法