1. 程式人生 > 實用技巧 >16.字串雜湊 雜湊表

16.字串雜湊 雜湊表

這個方法叫做字串字首雜湊法- -

先求出來每個字首的雜湊值

問題1:如何來定義某一個字首的雜湊值

把這個字串看成是一個P進位制的數

每一位上的字母的ascii碼,就是這一位上的數

最後mod上一個很小的數,就對映到0 ~Q - 1

這樣就可以把一個字串轉換為一個數字

注意事項1:

一般情況下,不能把某個字母對映成0

比如把A對映成0

那A,AA,AAA都是0了。這樣就把不同的字串對映成同樣的數字了,錯誤

注意事項2:

之前的雜湊方式是有處理衝突的機制的

這裡我們是假定不會有衝突的

從數學結論上看,在P = 131或13331,Q = 2 ^ 64的情況下

在99.99%的情況下,不會有衝突

至於為啥不會有衝突,這個就好比常見取模數是1000000001,1000000003,1000000007。可以直接記下來

問題2:這樣的雜湊方式再配合上字首雜湊,有啥好處

好處就是可以利用字首雜湊,計算出來每一個子串的雜湊值。字首和思想,萬物皆可字首和

[L, R]的雜湊值就可以用公式計算出來

我們直接用unsignedlonglong來儲存所有的h[]

這樣就不用對2 ^ 64取模了,溢位就等價於取模

預處理h[]陣列直接用

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 100010, P = 131;
 4 char s[N];
 5 typedef unsigned long long ULL;
 6 ULL h[N], p[N];
7 //p陣列用來儲存p的多少次方 8 ULL get(int l, int r) { 9 return h[r] - h[l - 1] * p[r - l + 1]; 10 } 11 //雜湊值是0 ~ 2 ^ 64 - 1之間的一個數 12 int main() { 13 int n, m; 14 cin >> n >> m >> s + 1; 15 p[0] = 1; //p的0次方等於1 16 for (int i = 1; i <= n; i++) { //從第一個字母開始 17 p[i] = p[i - 1
] * P; 18 h[i] = h[i - 1] * P + s[i]; 19 } 20 while (m--) { 21 int l1, r1, l2, r2; 22 cin >> l1 >> r1 >> l2 >> r2; 23 if (get(l1, r1) == get(l2, r2)) { 24 cout << "Yes" << endl; 25 } else { 26 cout << "No" << endl; 27 } 28 } 29 return 0; 30 }