字符串前缀哈希

Posted on 2022-03-10 15:31  ZheyuHarry  阅读(212)  评论(0编辑  收藏  举报

今天要介绍的是yxc都说是特别牛逼的一种算法,对于处理字符串问题十分的有用!

 

我们先大概的简介一下这个算法,我们在之前的普通哈希中我们已经知道哈希是需要定义一个哈希函数来使一个比较大的值域映射到一个较小的区间中,但是有可能有多个值映射到同一个值上,所以我们为了处理这样的冲突,我们分别创造了开放寻址法和拉链法;而且我们可以发现,我们在这里只需要去确定这个数字的存在性即可,是不需要保序的。

 

然而在这里我们要对字符串进行哈希时,我们需要对其中的每个字符保序,不然的话就会变成不同的字符串。所以我们这里就是把每个不同的字符串几乎一一映射成一个数字,我们将这个字符串看成是一个P进制的数组,每个字符的Ascii码就是P进制的数不同位上的值,然后我们还要将这个数模取一个较小的数Q;

根据一般经验而言,我们令这个P为131或13331,令Q为2^64时,几乎不会有冲突产生;

 

接下来先上板子再进行分析:

 

###

#include<bits/stdc++.h>
#define maxn 100010

using namespace std;
typedef unsigned long long ULL;
int P = 131;
ULL h[maxn],p[maxn];
char str[maxn];

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

int main()
{
int n , m;
p[0] = 1;
cin>>n>>m>>str+1;
for(int i = 1;i<=n;i++){
p[i] = p[i-1]*P;
h[i] = h[i-1]*P + str[i];
}

while(m--){
int l1,r1,l2,r2;
cin>>l1>>r1>>l2>>r2;
if(get(l1,r1) == get(l2,r2)) cout<<"Yes"<<'\n';
else cout<<"No"<<'\n';
}
return 0;
}

 

分析:我们要去确定两个字符串是否相同,我们只需要去看他的哈希值是否相同就行了。

我们在这里定义的p数组是记载p的次方:p[i] = P^i;      这里定义的h数组是指一个数,同时也代表了一个字符串,所以我们在计算h数组的时候,我们就相当于是把一个数字的不同位加在一起求其前缀和。所以我们在计算其中的子数组的时候,我们有以下公式: h[l,r]=h[r]−h[l−1]×P^(r−l+1)

就像是  34 = 1234 - 12*10^2;

这个字符串哈希的方式十分的普遍,所以我们可以将其运用到很多的场景中去!