理解KMP演算法

2022-02-20 00:49:10 字數 2991 閱讀 9923

由暴力匹配引入kmp演算法 ---->

問題:有乙個文字串s,和乙個模式串p,現在要查詢p在s中的位置。

如果用暴力匹配的思路,並假設現在文字串s匹配到 i 位置,模式串p匹配到 j 位置,則有:

示例:(上面s, 下面p)

比如從a這裡開始匹配上了:

一直這樣匹配下去:

到這裡匹配不上了:

就回滾回去重新開始:

這種回滾的問題在於:

在之前第4步匹配中,我們已經得知s[5] = p[1] = b,而p[0] = a,即p[1] != p[0],故s[5]必定不等於p[0],所以回溯過去必然會導致失配。

就是說,圖上s中紅框b我們之前就知道不等於下面這個紅框a了,回溯回去也沒用。

那有沒有一種演算法,讓i 不往回退,只需要移動j 即可呢?

yes===> kmp演算法,它利用之前已經部分匹配這個有效資訊,保持i 不回溯,通過修改j 的位置,讓模式串盡量地移動到有效的位置。

knuth-morris-pratt 字串查詢演算法,簡稱為 「kmp 演算法」,常用於在乙個文字串 s 內查詢乙個模式串 p 的出現位置,這個演算法由 donald knuth、vaughan pratt、james h. morris 三人於 1977 年聯合發表,故取這三人的姓氏命名此演算法。

下面先直接給出 kmp 的演算法流程(後續會詳述):

假設現在文字串s匹配到 i 位置,模式串p匹配到 j 位置:

示例:接著看上面的例子,到這裡發現匹配不到:

完整的例子

如果給定文字串「bbc abcdab abcdabcdabde」,和模式串「abcdabd」,現在要拿模式串去跟文字串匹配。

移動位數 = 已匹配的字元數 - 對應的部分匹配值

==> 最大長度

表  /  next陣列

原模式串子串對應的各個字首字尾的公共元素的最大長度表/next 陣列為:

我們看下上表是如何構造的:

最大長度值(也稱"部分匹配值")就是"字首"和"字尾"的最長的共有元素的長度。以"abcdabd"為例,

- "a"的字首和字尾都為空集,共有元素的長度為0;

- "ab"的字首為[a],字尾為[b],共有元素的長度為0;

- "abc"的字首為[a, ab],字尾為[bc, c],共有元素的長度0;

- "abcd"的字首為[a, ab, abc],字尾為[bcd, cd, d],共有元素的長度為0;

- "abcda"的字首為[a, ab, abc, abcd],字尾為[bcda, cda, da, a],共有元素為"a",長度為1;

- "abcdab"的字首為[a, ab, abc, abcd, abcda],字尾為[bcdab, cdab, dab, ab, b],共有元素為"ab",長度為2;

- "abcdabd"的字首為[a, ab, abc, abcd, abcda, abcdab],字尾為[bcdabd, cdabd, dabd, abd, bd, d],共有元素的長度為0。

再copy一遍上面的演算法流程:

示例匹配過程如下:

1. 因為模式串中的字元a跟文字串中的字元b、b、c、空格一開始就不匹配,直接將模式串不斷的右移一位即可,直到模式串中的字元a跟文字串的第5個字元a匹配成功:

2. 繼續往後匹配,當模式串最後乙個字元d跟文字串匹配時失配,模式串需要向右移動。但向右移動多少位呢?因為此時已經匹配的字元數為6個(abcdab),然後根據《最大長度表》可得失配字元d的上一位字元b對應的長度值為2,所以根據之前的結論,可知需要向右移動6 - 2 = 4 位。

3. 模式串向右移動4位後,發現c處再度失配,因為此時已經匹配了2個字元(ab),且上一位字元b對應的最大長度值為0,所以向右移動:2 - 0 =2 位。

4. a與空格失配,向右移動1 位。

6. 經歷第5步後(匹配cdabd的部分),發現匹配成功,過程結束。

通過上述匹配過程可以看出,問題的關鍵就是尋找模式串中最大長度的相同字首和字尾,基於此匹配。

參考 1

參考 2

參考 3

參考 4

理解KMP演算法(引用)

理解kmp演算法 引用 通用性的kmp演算法 void getnext st t,int next 由子串t求出next值 else k next k 滑動過程中如果出現不相等則認為以k個字元相等進行下一次滑動 kmpindex st s,st t,int pos maxstrlen為一常量,用來定...

KMP 演算法(個人理解)

相信大家看了 matrix67 的講解,一定已經知道了 kmp 演算法是怎麼回事,怎麼操作的,為什麼時間複雜度不高 這裡,我主要是分享我對 kmp 的理解 kmp 的精髓是什麼?這個東西,各自有個字的理解,很多人都覺得是避免了重複匹配,而我的理解是預處理 為什麼是預處理?你看看 kmp 的執行過程 ...

KMP演算法理解

kmp演算法的理解著實花了不少時間,幸好網上前輩的部落格寫得都相當好,結合幾篇部落格仔細想想還是可以理解的,這裡僅做一下整理。kmp演算法概念理解看這篇部落格就夠了字串匹配的kmp演算法by阮一峰 主要的邏輯那篇部落格都有講,求出next陣列,進行簡單的加減即可完成匹配。至於求解next陣列,則是k...