算法学习——字符串哈希(哈希算法)

字符串问题非常好用的一种方法:字符串哈希。

离散化本质上算是一类特殊的哈希算法。

所以哈希算法本质上是把变量通过某种映射关系,从原本的范围对应到新的某个范围。

字符串哈希的常用公式就是,假定字符串str和变量P 和变量Q;

字符串”abcdef“经过哈希的原理,我们将abcdef视作一个p进制的数,并且根据进制转换的原理,按权展开,然后将其转换为十进制的值并且modQ,得到的数就是对应的哈希值。

计算公式:hash[ "abcdef" ] = hash("abcdef") = (a * (p^4) + b * (p^3) + c * (p^2) + e * (p^1) + f * (p^0) ) mod Q;

然后当我们求这个字符串的L - R区间的子串hash值时,我们已知1-L的哈希值和1-R的哈希值,我们只需要把h[L - 1]*p[R-L+1]也就是把l向左移动L-R间距的距离使他们对齐,然后相减就可以得到。也就是说求区间L - R的哈希值公式 = h[R] - h[L - 1] * p [R - L +1];

例题:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
//经验:我们通常P取131 或者 13331 同时Q取2^64次方,能使得hash的冲突概率最低,达到最小
const ULL P = 131;
const int N = 100010;
/*
由于2的64次方正好是unsigned long long的最大值的所以溢出之后就等于取余Q
const unsigned long long Q = 2的64次方
*/

//h[]是存hash值的数组,p[]是存放p的次方的结果的数组
//哈希公式:hash("abcdef") = (a * (p^4) + b * (p^3) + c * (p^2) + e * (p^1) + f * (p^0) ) mod Q; 
ULL h[N],p[N];
//求区间L-R之间的字符串的hash值
//根据原理,如果想求L 至 R区间的字符串的hash值,我们已知1-L的哈希值和1-R的哈希值,我们只需要把
//h[L]*p[R-L+1]也就是把l向左移动L-R间距的距离使他们对齐,然后相减就可以得到。
ULL get(int l,int r){
    ULL res = 0;
    res = h[r] - h[l-1]*p[r-l+1];
return res;
}

int n,m;
char str[N];

int main(){
    ios::sync_with_stdio(0);
    cin.tie();
    cin>>n>>m;
    //str+1表示str的首地址向右偏移一位,也就是下标从1开始读入
    cin>>str+1;
    //初始化P[0] = 1;
    p[0] = 1;
    //预处理p[]数组和h[]数组
    for(int i = 1 ; i <= n ; i ++){
        p[i] = p[i-1] * P;
        //h[i-1]*p 意义是把1-(i-1)位的哈希值集体向左移动一位,然后加上当前第i位上的字符*p^0也就是*1
        h[i] = h[i-1] * P + str[i];
    }
    while(m--){
        //开始进行询问
        int l,r,L,R;
        cin>>l>>r>>L>>R;
        if(get(l,r) == get(L,R)){
            puts("Yes");
        }else puts("No");
        
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Flydoggie/p/12291217.html
今日推荐