KMP演算法詳細解讀

2021-07-24 14:19:51 字數 3263 閱讀 2811

備註:2016.11.18,寫kmp演算法千萬不要忘了初始化next[0]=-1。

ps:自從學會了寫偽**,現在演算法水平大大的提公升了。kmp看了別人的部落格看懂了,然後自己寫一次性就ac了。

kmp入門請參考這幾位大神:

先總結思路:

求next陣列的偽**是:

getnext()

j <- 0

k <- -1

next[0] <- -1

while j < length -1 do

if k == -1 or p[j] == p[k]

next[++j] <- ++k

else

k <- next[k]

return next

例如: 

設主串下標為i,模式串下標為j,k是next陣列對應的下標。符合條件k==-1 or p[j] == p[k]所走的分支下文稱1分支,k<-next[k]所在分支稱為2分支。

模式串: a b a b

0 1 2 3

首先該演算法對next[0]初始化為-1,因為如果第乙個字元不匹配,我們不可能向後回溯了。這個時候必須i <- i+1,j <- j+1,主串和模式串同時前進。

我們分迴圈走:

(1)第一次迴圈,j=0, k=-1,符合k==-1,所以走1分支,j和k分別加1,next[1]=0。在這裡我們要理解一下,j和k的含義。我們kmp匹配憑藉什麼,就是憑藉相同的前字尾,

所以k初始為-1,j初始為0,乙個在後面走,乙個在前面走,可以憑藉判斷p[j] == p[k]來判斷字元是否相等,計算前字尾相同的長度,進而得出我們的next匹配值。

顯然,第一次檢測字元a,a前面沒有任何前字尾相同,所以a的next值就是0。意味著a如果匹配失敗,要從下標0重新開始匹配。我們想一下,a本來就是字串第乙個元素,

我們在暴力匹配時,第乙個字元匹配失敗,不也正是再次用第乙個字元和主串中下乙個字元進行匹配嗎?

(2)第二次迴圈,j=1, k=0,不滿足k==-1,同時字串下標為1的元素是b,不滿足p[j]==p[k],所以進入2分支。因為k目前等於0,所以k=next[k]=next[0]=-1。然後再次進入

while迴圈。此時我們驚奇的發現再次k==-1,所以next[++j]即next[2]=++k=0。我們來闡述一下它的道理,當剛進本次迴圈時,j=1,k=0比較字元a和b不等,這說明什麼問

題呢,說明b的下乙個元素的前面元素前字尾相同的個數為0。是的,a,b沒有乙個相同的,下乙個元素如果匹配失敗,我們不能利用前字尾的特性少回溯一部分,必須從頭

重新開始比較,所以k=0。通過(1)(2)兩步我想已經很明白了,只要乙個元素前面的部分前字尾相同個數為0,那該元素的next值就為0。一旦該元素匹配失敗,我們就相當

於用暴力匹配的方法,再次比較。

(3)第三次迴圈,j=2, k=0, 這次p[j]==p[k]==a,所以走1分支,next[++j]即next[4]=++k=1,因為第三個元素a和第乙個元素a相同,那麼第四個元素前面元素前字尾相同的長

度就為1。當第四個元素匹配失敗時,由於我們知道它前面部分前字尾相同長度為1,在程式中表現為next值next[4]=1,所以我們只需從下標1的位置和當前匹配失敗位置進行

比較即可。

如: a b a c

a b a d

這個匹配失敗,那我們下一次直接這樣:

a b a c

a b a d

這樣不是很好嗎,下面的第乙個元素a和上面的三個元素a既然相等,我們幹嘛還要比較。通過next值,我們就可以知道不用比較哪些元素了,效率相比暴力解法有了很

大提公升,暴力解法時間複雜度是o(mn),而kmp演算法的時間複雜度則是o(m+n)。

在上面中,我們給出了getnext()函式,但是它還是有優化的餘地的。

比如: a b a c

a b a b

這樣匹配,第二個b匹配失敗,由我們之前的getnext()方法求得的next陣列為 ,所以b對應的next值為1,我們將從下標1重新開始匹配,但是

a b a c

a b a b

這樣匹配有意義嗎?明知道b已經在該位置匹配失敗了。所以我們盡可能要略過此次比較,與其此次比較完,從next[1]=0重新開始比較,不如直接略過他,一步到位。

當出現p[++j]==p[++k]的時候,我們不再讓next[++j]的值為為k,直接讓它等於next[k]即可,就可達到略過的目的。

偽**如下:

getnext()

j <- 0

k <- -1

next[0] <- -1       //不要忘了初始化這一步

while j < length -1 do    //千萬注意是小於length-1,而不是length,是從前乙個推下乙個,到不了下標為length-1的元素

if k == -1 or p[j] == p[k]

if p[++j] == p[++k]

next[j] <- next[k]

else

next[j] <- k

else

k = next[k]

return next

下面給出kmp演算法偽**

kmp(s1,s2)

i <- 0

j <- 0

next <- getnext()

while i < s1.length and j < s2.length do

if j == -1 or s1[i] == s2[j]     //如果j==-1,j也要歸為0,重新匹配

i <- i + 1

j <- j + 1

else

j <- next[j]      //j的next值可能為-1

if j == s2.length      //千萬注意:當j==s2.length時才說明匹配完畢,而不是用s1比較

return i - j

else return -1

**如下:

#include #include #include int* get_next(const std::string& s, const int len)

else

} return next;

}int kmp(const std::string& s1, const std::string& s2)

else

j = next[j]; }

delete next;

return j == len_s2 ? (i - j) : -1; //記住判斷j是否匹配完畢

}int main()

alpha blending演算法 詳細解讀

一幅彩色影象的每個畫素用r,g,b三個分量表示,若每個分量用8位,那麼乙個畫素共用3x8 24位表示。在用32位表示乙個畫素時,若r,g,b分別用8位表示,剩下的8位常稱為 通道 alpha channel 位。它用來表示該畫素如何產生特技效果,即通常我們說的半透明。alpha的取值一般為0到255...

KMP詳細解釋及KMP演算法模板

kmp是什麼,kmp解決什麼型別的問題 kmp全稱為knuth morris pratt演算法,是一種高效的字串匹配演算法,尋找乙個字串中是否包含另乙個字串,例如 char s ababababcab char p ababc s為模板串 主串 p為子串,在s中找到p的位置 暴力匹配演算法 o n ...

KMP演算法的詳細講解

kmp演算法是一種改進的字串匹配演算法。講述kmp演算法之前,我們要先建立乙個概念,沒有這個概念,kmp很難理解。那,我們先忘掉原問題,來進行乙個概念建設。這個概念就是 在乙個字串中,乙個字元之前的字串最長字首和最長字尾的匹配長度,有點繞,我們舉個例子吧 對於字元d,我們想求乙個資訊,就是d之前的字...