對於任意乙個串,串中字符集的大小為d,則該串中的任意乙個字元都可以用乙個d+1進製的整數來表示。需要注意的是,這裡是d+1進製,而不是d進製,是因為不能用0來表示任意乙個字元,否則如果該字元組成串的乙個字首,無論字首的長度多少,都不會影響串所對應的整數取值。
rabin-karp演算法,它是字串快速查詢的一種演算法,解決思路是把乙個字串,看作是字符集長度進製的樹,如果是ascii,這個進製就是128,如果是只考慮英文小寫字母,那這個進製就是26,通過數值的比較得出字串的比較結果。
如果我們要在 ascii 字符集範圍內查詢「搜尋詞」,由於 ascii 字符集是0~127一共 128 個字元,那麼 d 就等於 128,比如我們要在字串 「abcdefg」 中查詢 「cde」,那麼我們授信計算模式字串 「cde」的hash指紋:
n=len(「cde」)
d=128
hash(cde)= c_ascii*d^(n-1)+ d_ascii*d^(n-2)+ e_ascii*d^(n-3)
=99*128^2+100*128^1+101*128^0
=1634917
模式字串的hash值計算完之後開始計算源串的hash值,計算方法與上面相同:
hash(abc)= a_ascii*d^(n-1)+ b_ascii*d^(n-2)+ c_ascii*d^(n-3)
=97*128^2+98*128^1+99*128^0
=1601891
其中:hash(a)= a_ascii*d^(n-1) =97*128^2= 1589248
hash(b)= b_ascii*d^(n-1) =98*128^1= 12544
hash(c)= c_ascii*d^(n-1) =99*128^0=99
顯而易見的hash(abc)不等於hash(cde),源串的視窗向後滑動一位計算hash(bcd), hash(bcd)的計算如果還是按照上面的方法的話rabin-karp的時間複雜度和暴力解法一樣也是o(m*n),hash(bcd) 可以看成hash(abc)中去掉hash(a),然後加入hash(d),如此一來就將計算指紋的時間複雜度由o(n)降低到o(1):
hash(bcd)= (hash(abc)- hash(a))*d+ hash(d),這樣就可以繼續比較 「cde」 和 「bcd」 是否匹配,以此類推。
由上面的描述可以推導出更一般的規律如下:
hash( txt[s+1 .. s+m] ) = ( d ( hash( txt[s .. s+m-1]) – txt[s]*h ) + txt[s + m] ) mod q
hash( txt[s .. s+m-1] ) : hash value at shift s .
hash( txt[s+1 .. s+m] ) : hash value at next shift (or shift s +1)
d : number of characters in the alphabet
q : a prime number
h: d^(m-1)
加入模q後,h = h』mod q.對於指紋相同的串還要在進行一次比對校驗,如果q足夠大,碰撞的機率會很少出現。
rabin-karp演算法的思想:
假設子串的長度為m,目標字串的長度為n
計算子串的hash值
計算目標字串中每個長度為m的子串的hash值(共需要計算n-m+1次)
比較hash值
如果hash值不同,字串必然不匹配,如果hash值相同,還需要使用樸素演算法再次判斷
為了快速的計算出目標字串中每乙個子串的hash值,rabin-karp演算法並不是對目標字串的 每乙個長度為m的子串都重新計算hash值,而是在前幾個字串的基礎之上, 計算下乙個子串的 hash值,這就加快了hash之的計算速度,將演算法中的內迴圈的世間複雜度從o(m)將到了o(1)。
**示例:
d取字符集的個數
#define d 256
/* s -> search sequence
t -> target sequence
q -> a prime number
*/void search(char *s, char *t, int q)
for (i = 0; i <= n - m; i++)
if (j == m)
}if ( i < n-m )
}}
演算法之 字串匹配演算法
一說到兩個字串匹配,我們很自然就會想到用兩層迴圈來匹配,用這種方式就可以實現乙個字串是否包含另乙個字串了,這種演算法我們稱為 bf演算法。bf演算法,即暴力 brute force 演算法,是普通的模式匹配演算法,bf演算法的思想就是將目標串 s 的第乙個字元與模式串 t 的第乙個字元進行匹配,若相...
字串匹配演算法 字串匹配演算法總覽
字串匹配在文字處理裡非常重要,我們採用簡潔的python 把以下演算法一一實現並講解。樸素演算法 algorithm rabin karp 演算法 有限自動機演算法 finite automation knuth morris pratt 演算法 kmp algorithm boyer moore ...
字串匹配演算法之BF vs KMP
最笨的方法bf,暴力匹配,無需多說,最難理解的是kmp演算法,費了好大勁才弄明白。要理解kmp演算法,其實最關鍵的是生成標明下次匹配位置的next陣列。其意義是,如果當前匹配到模式字串的第j個字元是失配,則只需要將j重置為next j 後,繼續向後匹配即可。next j 的值表示p 0.j 1 中最...