KMP演算法解析

2021-09-06 20:28:44 字數 2292 閱讀 1235

今天來說說這個難以理解的kmp演算法。之前寫過乙個模板,一直去套用,實在愧對演算法二字,今天悟一下。

kmp演算法完成的任務是:給定兩個字串o和f,長度分別為n和m,判斷f是否在o中出現,如果出現則返回出現的位置。常規方法是遍歷a的每乙個位置,然後從該位置開始和b進行匹配,但是這種方法的複雜度是o(nm)。kmp演算法通過乙個o(m)的預處理,使匹配的複雜度降為o(n+m)。

我們首先用乙個圖來描述kmp演算法的思想。在字串o中尋找f,當匹配到位置i時兩個字串不相等,這時我們需要將字串f向前移動。常規方法是每次向前移動一位,但是它沒有考慮前i-1位已經比較過這個事實,所以效率不高。事實上,如果我們提前計算某些資訊,就有可能一次前移多位。假設我們根據已經獲得的資訊知道可以前移k位,我們分析移位前後的f有什麼特點。我們可以得到如下的結論:

所以前移k位之後,可以繼續比較位置i的前提是f的前i-1個位置滿足:長度為i-k-1的字首a和字尾b相同。只有這樣,我們才可以前移k位後從新的位置繼續比較。

所以kmp演算法的核心即是計算字串f每乙個位置之前的字串的字首和字尾公共部分的最大長度(不包括字串本身,否則最大長度始終是字串本身)。獲得f每乙個位置的最大公共長度之後,就可以利用該最大公共長度快速和字串o比較。當每次比較到兩個字串的字元不同時,我們就可以根據最大公共長度將字串f向前移動(已匹配長度-最大公共長度)位,接著繼續比較下乙個位置。事實上,字串f的前移只是概念上的前移,只要我們在比較的時候從最大公共長度之後比較f和o即可達到字串f前移的目的。

理解了kmp演算法的基本原理,下一步就是要獲得字串f的每乙個以首字母開頭的子串的前字尾最大公共部分長度。我們記為next陣列。在這裡要注意一點,next陣列表示的是長度,下標從1開始;但是在遍歷原字串時,下標還是從0開始。next[i]表示的是前i個字元的最大公共前字尾長度。假設我們現在已經求得next[1]、next[2]、……next[i],分別表示長度為1到i的字串的字首和字尾最大公共長度,現在要求next[i+1]。由上圖我們可以看到,如果位置i和位置next[i]處的兩個字元相同(下標從零開始),則next[i+1]等於next[i]加1。如果兩個位置的字元不相同,我們可以將長度為next[i]的字串繼續分割,獲得其最大公共長度next[next[i]],然後再和位置i的字元比較。這是因為長度為next[i]字首和字尾都可以分割成上部的構造,如果位置next[next[i]]和位置i的字元相同,則next[i+1]就等於next[next[i]]加1。如果不相等,就可以繼續分割長度為next[next[i]]的字串,直到字串長度為0為止。

見**:

void

get_next()

else

if(j<0

) }}}

計算完成next陣列之後,我們就可以利用next陣列在字串o中尋找字串f的出現位置。匹配的**和求next陣列的**非常相似,因為匹配的過程和求next陣列的過程其實是一樣的。假設現在字串f的前i個位置都和從某個位置開始的字串o匹配,現在比較第i+1個位置。如果第i+1個位置相同,接著比較第i+2個位置;如果第i+1個位置不同,則出現不匹配,我們依舊要將長度為i的字串分割,獲得其最大公共長度next[i],然後從next[i]繼續比較兩個字串。

見**:

int

kmp()

if(j==len) return i-j+1

;

else

return -1

;}

故而最後完整的**:

1 #include 2 #include 3 #include 4 #include 5

using

namespace

std;67

char s[100],t[100];8

int next[50

],len,ls;910

void

get_next();

11int

kmp();

1213

intmain()

22void

get_next()else

34if(j<0)38

}39}40

}41intkmp()

47if(j==len) return i-j+1;48

else

return -1

;49 }

KMP演算法解析

日期 2013年5月 1日 字串匹配是計算機的基本任務之一。舉例來說,有乙個字串 bbc abcdab abcdabcdabde 我想知道,裡面是否包含另乙個字串 abcdabd 許多演算法可以完成這個任務,knuth morris pratt演算法 簡稱kmp 是最常用的之一。它以三個發明者命名,...

KMP演算法解析

kmp 演算法是用來求乙個較長字串是否包含另乙個較短字串的演算法,其中難點在於求解 next 陣列。next 陣列含義為 如果匹配到該字元時失敗,回溯的位置。straba abca cpos01 2345 67next 10 0112 01其中,next 陣列首位設定為 1,意味著首位匹配失敗時無法...

KMP演算法深度解析

摘要 kmp演算法是字串匹配的經典演算法,由於其o m n 的時間複雜度,至今仍被廣泛應用。大道至簡,kmp演算法非常簡潔,然而,其內部卻蘊含著玄妙的理論,以至許多人知其然而不知其所以然。本文旨在解開kmp演算法的內部玄妙所在,希望能夠有助於學習與理解。1 kmp演算法 一種改進的字串匹配演算法,由...