KMP字符串匹配算法


KMP字符串匹配算法

/編輯

KMP完全匹配算法和 Levenshtein相似度匹配算法是模糊查找匹配字符串中最經典的算法,配合近期技術欄目關於算法的探討,從網上摘取了一些簡要的內容,加上自己的一些理解,向大家普及一些這方面的知識,希望能拋磚引玉。

l  算法簡介:

kmp算法是一種改進的字符串匹配算法,由D.E.KnuthV.R.PrattJ.H.Morris同時發現,因此人們稱它為克努特——莫里斯——普拉特操作(簡稱KMP算法)。KMP算法的關鍵是根據給定的模式串W1,m,定義一個next函數。next函數包含了模式串本身局部匹配的信息。

l KMP算法和傳統算法的匹配比較:

1.      傳統算法:

         傳統匹配思想是,從目標串Target的第一個字符開始掃描,逐一與模式串的對應字符進行匹配,若該組字符匹配,則檢測下一組字符,如遇失配,則退回到Target的第二個字符,重復上述步驟,直到整個PatternTarget中找到匹配,或者已經掃描完整個目標串也沒能夠完成匹配為止。假設模式串Pattern長度為m,目標串Target長度為n,則每次比較最多需要花費O(m)的時間,算法的復雜度為O((n-m+1)*m)。這種算法沒有利用匹配過的信息,每次都從頭開始比較,速度很慢。

2.      KMP算法:

在傳統算法的基礎上,當匹配失敗后,並不簡單地從目標串下一個字符開始新一輪的檢測,而是依據在檢測之前得到的有用信息,或者說模式串本身的特征信息,取得next函數跳轉的位置,直接跳過不必要每次從頭檢測,從而達到一個較高的檢測效率。

l 算法實例說明:

假設在串S=abcabcabdabba中查找T= abcabd

1.      傳統算法:

先是比較S[0]和T[0]是否相等,然后比較S[1] 和T[1]是否相等我們發現一直比較到S[5] 和T[5]才不等。如圖:

 

當這樣一個失配發生時,T下標必須回溯到開始,S下標回溯的長度與T相同,然后S下標增1,然后再次比較。如圖:

這次立刻發生了失配,T下標又回溯到開始,S下標增1,然后再次比較。如圖:


這次立刻發生了失配,T下標又回溯到開始,S下標增1,然后再次比較。如圖:



又一次發生了失配,所以T下標又回溯到開始,S下標增1,然后再次比較。這次T中的所有字符都和S中相應的字符匹配了。函數返回TS中的起始下標3。如圖:

2.      KMP算法:

還是相同的例子,在S=abcabcabdabba中查找T=abcabd,如果使用KMP匹配算法,當第一次搜索到S[5]T[5]不等后,如圖:

S下標不是回溯到1T下標也不是回溯到開始,而是根據TT[5]==d的模式函數值(next[5]=2),直接比較S[5] T[2]是否相等,因為相等,ST的下標同時增加;因為又相等,ST的下標又同時增加。。。最終在S中找到了T。如圖:

此處關鍵的問題是,為什么KMP算法能聰明的知道應該直接從S[5] T[2]開始比較呢?因為它能夠利用已經得到的部分匹配信息來進行過濾。因為我們根據第一次比較得到的結果,如圖:

很明顯已經匹配了到了部分結果”abcab”,只是由於到T[5]==’d’的時候才無法和S[5]=’c’匹配上的,此時按傳統算法T[0]應該重新開始和S[1]比較,但是根據之前的匹配結果S[1]等於T[1],但很明顯T[0]不等於T[1],因此比較T[0]S[1](也即T[1])是完全沒有必要的。

            以此類推,根據已經得到的結果”abcab”T[0]重新開始比較的時候,應該和S[3](也即T[3])開始比較才是明智的。

因此 next[5]=2這個2表示T[5]==d的前面有2個字符和開始的兩個字符相同,且T[5]==d不等於開始的兩個字符之后的第三個字符(T[2]=c.如圖:

 

也就是說,如果開始的兩個字符之后的第三個字符也為d,那么,盡管T[5]==d的前面有2個字符和開始的兩個字符相同,T[5]==d的模式函數值也不為2,而是為0

附件為KMP算法的實現java,有興趣的同事可以試試:

KMPMatchString.java

 






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM