字串雜湊(詳解+模版)
阿新 • • 發佈:2018-12-10
參考部落格:
個人理解:
字串Hash的種類還是有很多種的,不過在ACM中一般只會用到一種名為“BKDR Hash”的字串Hash演算法。它的主要思路是選取恰當的進位制,可以把字串中的字元看成一個大數字中的每一位數字。關於進位制的選擇實際上非常自由,大於所有字元對應的數字的最大值即可,比如一個字符集是a到z的題目,選擇27、233、19260817都是可以的。一般使用李煜東前輩的給出的值——131或13331,此時衝突概率極低。
使用雜湊陣列Hash[i]儲存字首:一般設Hash[0]=0 。
=>
...
因此,區間 [l,r] 的雜湊值為 。
我們看到雜湊函式中存在指數級,所以一般都需要%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開始就沒這種問題了。