KMP演算法詳細介紹及Java實現

2021-09-22 05:58:59 字數 2867 閱讀 5587

kmp是三位大牛:d.e.knuth、j.h.morris和v.r.pratt同時發現的。其中第一位就是《計算機程式設計藝術》神作的作者。

kmp演算法要解決的問題就是在字串(也叫主串)中的模式(pattern)定位問題。說簡單點就是我們平時常說的關鍵字搜尋。模式串就是關鍵字(接下來稱它為p),如果它在乙個主串(接下來稱為t)**現,就返回它的具體位置,否則返回-1(常用手段)。

舉個例子:

// 這裡也可以使用for迴圈的方式,不管哪種方式複雜度都是o(nk)

public

static

boolean

issubstring

(string s1, string s2)

else

}return j == s2.

length()

;}

上面這個方法可以計算出來,但是裡面存在一些無效的計算,對於例子來說,如果是手工匹配的話,如果第一次匹配不成功我們下一次會直接從2位置開始匹配,因為1位置不是a顯然是不可以的。這個時候我們可能會想,那這樣的話我可以將主串中a出現的位置記錄下來,每次匹配不成功就直接跳到下乙個a所在的位置。這種方式是對上面方法的優化,有那麼點兒意思,但是還不夠,例如下面例子: 採用記錄的方式與暴力沒有區別。

有了上面優化的思想,我們猜測肯定有更優的方式,只是需要做一些特殊的處理,這個時候大牛們就發明了kmp演算法,其思想就是:「利用已經部分匹配這個有效資訊,保持i(主串指標)指標不回溯,通過修改j(模式串指標)指標,讓模式串盡量地移動到有效的位置。」所以,整個kmp的重點就在於當某乙個字元與主串不匹配時,我們應該知道j指標要移動到哪?

舉個例子來說明:

c 和d不匹配,那麼下一次我們該將j移動到什麼位置,顯然是位置1,因為前面只有乙個a:

下面情況也是一樣的:

c和b不匹配,下一次我們應該將j移動到位置2:

至此我們可以總結出一些規律,當匹配失敗時,j要移動的下乙個位置k。存在著這樣的性質:最前面的k個字元和j之前的最後k個字元是一樣的。用數學公式來表示是這樣的

p[0 ~ k-1] == p[j-k ~ j-1]

證明:當t[i] != p[j]時

有t[i-j ~ i-1] == p[0 ~ j-1]

由p[0 ~ k-1] == p[j-k ~ j-1]

必然:t[i-k ~ i-1] == p[0 ~ k-1]

可以通過下圖來理解:

首先分析j為0的時候,這個時候如果匹配失敗,只能移動i指標,因為j已經在最左側沒有地方可以移動;

分析j為1的時候,這個時候如果匹配失敗,需要將j移動到0位置,因為其前面只有0這乙個位置;

下面分析一些一般的情況:

仔細對比上面兩個圖我們發現:當p[k] == p[j]時,有next[j+1] == next[j] + 1

證明:因為在p[j]之前已經有p[0 ~ k-1] == p[j-k ~ j-1]。(next[j] == k)

這時候現有p[k] == p[j],我們是不是可以得到p[0 ~ k-1] + p[k] == p[j-k ~ j-1] + p[j]。

即:p[0 ~ k] == p[j-k ~ j],即next[j+1] == k + 1 == next[j] + 1。

那如果p[k] != p[j]呢?只需要讓k=next[k];

因為不相等,所以當j變成nextj的時候還是不能匹配的,下一次需要將j變成next[k],這裡的k是上一輪的結果,這裡本應該放個圖的但是插不進來了,所以可以自己畫畫。

這樣的話就可以寫kmp演算法了,只是將上面暴力搜尋稍加改變,在下一輪的時候根據next陣列進行確定。

下面實現next陣列的時候又加了乙個小優化,如果p[j] == p[next[j]]這個時候可以直接跳過,即直接讓next[j]=next[k];為什麼可以這樣吶,舉個例子:

主串:abacbcd

配串:abab

如果是這種情況,根據求next的方法,next陣列為[-1, 0, 0, 1]

但是下一步我們在移動的時候發現,如果j移動到1位置,b和c還是不能匹配,所以可以直接跳過。

/**

* kmp演算法實現

* 1. 先實現next資料生成

* 2. 然後根據next資料進行匹配

*/public

static

int[

]getnext

(string s)

else

}else

}return next;

}// s1 is main string ,s2 is pattern string

public

static

intkmp

(string s1, string s2)

else

}return j == s2.

length()

? i - j :-1

;}

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

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

Java集合詳細介紹及原理

collection 單列集合 list 有序,可重複 arraylist 底層資料結構是陣列,查詢快,增刪慢 執行緒不安全,效率高 vector 底層資料結構是陣列,查詢快,增刪慢 執行緒安全,效率低 linkedlist 底層資料結構是鍊錶,查詢慢,增刪快 執行緒不安全,效率高 set 無序,唯...

java演算法篇KMP演算法及應用

給定兩個字串,判斷是否乙個字串包含另外乙個字串,如果包含,返回起始位置。比如 string str1 abceacmk32acmzq string str2 acm 可以看出,str1包含兩處str2,下面紅色地方 abceacmk32acmzq 返回4和10.遍歷str1,先匹配第乙個,如果不相同...