算法學習——字符串哈希(哈希算法)


字符串問題非常好用的一種方法:字符串哈希。

離散化本質上算是一類特殊的哈希算法。

所以哈希算法本質上是把變量通過某種映射關系,從原本的范圍對應到新的某個范圍。

字符串哈希的常用公式就是,假定字符串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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM