字串匹配定義:文字是乙個長度為n的陣列t[1…n], 模式是以個長度m<=n的陣列p[1…m]
p和t的元素都是有限字母表∑中的字元
1.字串樸素匹配
也就是蠻力匹配,每次移動乙個步長,然後匹配,時間複雜度o((n-m+1)m)
2.rabin-karp演算法
rabin-karp演算法的思想是將模式串p表達為乙個值,這樣每次進行串匹配的時候,只需要比較這個值就可以了,而不需要對m個字串進行m次比較。
核心思想是用 乙個值 來代替 整個字串 來參與比較
比如以十進位制為例,文字串為'1234567',模式串為'234'(其值為234),當搜尋指標指向第乙個字元'1'時,計算出串'123'的值為123,直接與模式串的值234進行比較,不匹配,那麼就表明此時模式串匹配失敗,將搜尋指標移向下乙個字元。
如何用 值 來代表 字串?
想象一下將字串轉換為數值的情形
計算串"123"的值:1*100+2*10+3*1 = 123
串"6789"的值:6*1000+7*100+8*10+9*1 = 6789
十進位制字母表只有0-9,因此選取基數10可以完成的表述整個串
對於ascii字母表,則可以選取基256。
因此,將乙個串表述成乙個值是可行的,其時間複雜度為o(m),其中m為串的長度。
對於文字串t[1…n],可以在o(m)的時間複雜度計算出前m個字元t[1…m]的值。
而t[2…m+1],t[3…m+2],...t[n-m+1…n]的值,可以在o(n-m)的時間計算出來(動態規劃)。
新的問題:值太大,溢位?
通過乙個值來表述乙個串以後,如果串比較長,那麼這個表述串的這個值自然會比較大,而且,可能會溢位。很自然的解決辦法是對這個值取模,將它限制到乙個固定的範圍內。
那麼問題又來了,模運算是多對一對映,比如,55和66對11取模後都是0,但是它們的值並不相等。
因此,取模運算會導致乙個新的問題,就是偽命中。也就是,模運算匹配,但串本身並不匹配。
可以顯式的檢查t[i…m+i]與p[1…m]是否相等。
假設計算的值對q取模,倘若q夠大,那麼t[i…m+i]的值與p[1…m]的值發生偽命中的機率就會比較低,那麼額外的測試時間就足夠低了。
這樣看來,對字串求值,通過值來進行串的匹配,更像乙個啟發式的思想,對文字串進行一次過濾,然後在進行逐字匹配。
由於每次在判定模式串是否匹配時,只需要進行一次比較,因此匹配過程中的期望時間複雜度為o(n-m+1),這個時間沒有加上對模式串求值的時間o(m)。最壞是時間複雜度也為o((n-m+1)m),也就是每一次唯一產生的值都與串的值取模相等,但實際情況下比蠻力匹配要快許多。
3.fa
針對模式串,構造乙個有窮自動機,那麼,有窮自動機接收的語言就是該模式串匹配的句子。
對於每個模式串,都存在乙個字串匹配自動機,必須在預處理階段,根據模式構造出相應的自動機後,才能利用它來搜尋字串。構造自動機的核心是構造其狀態轉移函式。
這種方法功能比較強大,因為它可以搜尋以正則式表達的模式串。而其他演算法則不能。
4.kmp
先看乙個例子。文字串t為bababaabcccb,模式p為ababaca
如圖所示。此時,紅色的5個字元ababa已經匹配,
從字元c開始不匹配。這時候開始移動模式p。到底該移動幾個字元呢?樸素的字串匹配移動一位,然後重新開始比較。但是根本模式本身的資訊,移動s'=s+1是無效的,s'=s+2才有可能導致乙個成功的匹配。因為模式p的前5個字元裡,ababa的前面三個字元aba同時也是ababa的字尾。也就是說,p的最長字首同時也是p5的的乙個真字尾。這些資訊是可以被預先計算的,用字首函式π來表示。在位移s處有q個字元成功匹配,那下乙個可能有效的位移為s'=s+(q-π[q]).
首先假定文字串從第s個位置開始與模式匹配,共匹配q個字元,匹配第q+1個字元時失敗,即滿足:p[1…q]=t[s+1…s+q],那麼,我們的目標就是,尋找乙個位移s',使得移動1,2,..s'-1都是不可能導致與模式p匹配成功,只有移動s',才有可能使得與模式p匹配成功。那該怎麼尋找這個位移呢?關鍵就在這個模式本身了。
如果p[1…q]已經匹配成功,在q+1處匹配失敗,倘若已知p[1…k]=p[q-k+1…q](k這個k就包含了模式串本身的資訊。它預先被計算,被定義為字首函式。定義如下:
模式p的字首函式是函式π(0,1,2,...,m-1}→並滿足
π[q]=max;
解釋一下,如果字元x在模式p中沒有出現,那麼從字元x開始的m個文字顯然不可能與p匹配成功,直接全部跳
過該區域即可。如果x在模式p中出現,則以該字元進行對齊。
2) 好字尾規則
p中的某一子串p[j-s+1..m-s]與已比較部分p[j+1..m]相同,可讓p右移s位。
delta2的定義如下:
delta2(j)=
(這部分還看得暈乎暈乎的,下次在來完善)
貼個bm例子
移動的時候,取兩者較大值作為位移值移動。
bm演算法在字母表很大,模式串很長時尤其適用,能夠顯著提高匹配速度。
實際應用中,bm演算法比同樣具有o(m+n)時間複雜度的kmp演算法效率高出3-5倍。具體來說,bm演算法的預處理階段的時間空間複雜性是o(m+n),查詢階段的時間複雜性是o(mn),最好情況下的效能是o(n/m)。
參考:前面幾個演算法主要參考《演算法導論》
bm演算法參考
字串匹配演算法 字串匹配演算法總覽
字串匹配在文字處理裡非常重要,我們採用簡潔的python 把以下演算法一一實現並講解。樸素演算法 algorithm rabin karp 演算法 有限自動機演算法 finite automation knuth morris pratt 演算法 kmp algorithm boyer moore ...
字串匹配演算法
首先引用一下另一篇文章中對字串匹配的介紹 字串匹配指的是從文字中找出給定字串 稱為模式 的乙個或所有出現的位置。本文的演算法一律輸出全部的匹配位 置。模式串在 中用x m 來表示,文字用y n 來,而所有字串都構造自乙個有限集的字母表 其大小為 根 據先給出模式還是先給出文字,字串匹配分為兩類方法 ...
字串匹配演算法
平常操作文字的時候,經常需要操作對字串進行操作。而字串中最重要的一種操作就叫匹配,字串的匹配演算法很多,人們最熟悉的莫過於kmp演算法了。今天就來談一談一些字串匹配演算法。先來說說大名鼎鼎的kmp演算法,這個演算法出現在無數的資料結構與演算法書上面。它的策略很簡單 當模式串第k個字元不匹配主串中第s...