1. 程式人生 > >字串雜湊(詳解+模版)

字串雜湊(詳解+模版)

參考部落格:

詳解1

詳解2

詳解3

個人理解:

字串Hash的種類還是有很多種的,不過在ACM中一般只會用到一種名為“BKDR Hash”的字串Hash演算法。它的主要思路是選取恰當的進位制,可以把字串中的字元看成一個大數字中的每一位數字。關於進位制的選擇實際上非常自由,大於所有字元對應的數字的最大值即可,比如一個字符集是a到z的題目,選擇27、233、19260817都是可以的。一般使用李煜東前輩的給出的值——131或13331,此時衝突概率極低

使用雜湊陣列Hash[i]儲存字首:一般設Hash[0]=0 。

Hash[i]=s[1]*P^{i-1}+s[2]*P^{i-2}+s[3]*P^{i-3}+...+s[i]

=>

Hash[0] = 0

Hash[1] = s[1]

Hash[2] = s[1]*P+s[2]

Hash[3] = s[1]*P^{2} + s[2]*P+s[3]

Hash[4] = s[1]*P^{3} + s[2]*P^{2}+s[3]*P+s[4]

...

因此,區間 [l,r] 的雜湊值為  Hash(l,r) = Hash[r]-Hash[l-1]*P^{r-l+1}

我們看到雜湊函式中存在指數級,所以一般都需要%MOD,我們一般取MOD=2^64,即用unsigned long long型別儲存雜湊值,讓其自然溢位就好,因為此型別是不會出現負數的(無符號位)。

 

模版:

for(int i = 1; i <= n; ++i) hash[i] = hash[i - 1] * P + str[i] - 'a';  
inline ull getsub(int l, int r) {return hash[r] - hash[l - 1] * bin[r - l + 1];}  

bin[i]表示 P 的 i 次方,一般用O(n)打表而不用快速冪,因為多個log(n)可能會出事...

 

雜湊須知:

兩個元素若全等,其雜湊值必定也相等;但雜湊值相等,兩個元素未必全等(雜湊值相等是兩個元素全等的必要不充分條件)。

即Hash時是儘量使衝突概率趨近於0,(儘量的滿足其充分性),因此,臉黑的時候可能會同一個程式碼第一遍不過,第二遍過...

此外,字串每種元素的值都要至少從1開始,不要從0開始。比如說小寫字母,如果從0開始,即a=0,b=1,...,z=25,那麼b和ab的雜湊值會相同,這時候就會發生衝突,但從1開始就沒這種問題了。