我對KMP演算法的理解

2021-08-10 00:16:07 字數 2427 閱讀 5833

我對kmp演算法的理解

在過去的幾天,我讀了好幾篇關於「利用kmp演算法查詢字串的解釋」的文章。出於某些原因,沒有一篇是能令我接受和理解的。每當讀到「字首的字尾的字首...」這些字眼時,我都有種拿頭撞牆的衝動。。。

最後,經過30分鐘反覆閱讀clrs的幾段文章,我決定坐下來找一些關於文字串匹配的例子,並把過程寫出來。現在我已經理解了kmp演算法並且能解釋它了。下面是我用自己的語言對它的解釋,但是在這裡我不會去闡釋它為什麼是高效的,網上已經有很多優秀的闡釋了。我會按我所理解的去詳細解釋它是怎樣運作的。

部分匹配表

kmp最關鍵的部分當屬部分匹配表了,以前我不能理解kmp的最大障礙就是不能清楚的理解部分匹配表的含義。下面我會盡可能用簡單的語言去解釋部分匹配表。

這是字串「abababaca的部分匹配表:

如果我有乙個有8個字元的文字串(就當它是"abababca"好了), 我的部分匹配表就含有8個元素。如果我看的是匹配表最後乙個元素,那麼我關心的就是整個文字("abababca"), 如果我看的是第7個元素,我關心的就是文字串的前7個字元("abababc"),此時最後乙個字元"a"是無關緊要的。同樣,如果我看的是匹配表的第6個元素... ***...注意,我還沒有討論匹配表的每個元素的含義,僅僅討論了它們代表什麼。

現在,為了討論他們的含義,我們首先要知道什麼是文字串的字首和字尾。

字首:乙個文字串中去掉最後乙個字元的所有組合("s", "sn", "sna", "snap"都是文字串"snape"的字首)。

字尾:乙個文字串中去掉第乙個字元的所有組合("e", "pe", "ape", "nape"都是文字串"snape"的字尾)。

知道了這些,我們就可以用一句話來解釋部分匹配表的含義了:

(子)文字串中字首字尾最長公共元素的長度

讓我來解釋一下,現在我們看匹配表的第3個元素,如上所述,此時我們關心的是文字串的前三個字元("aba"),"aba"中有兩個字首("a","ab")和兩個字尾("a","ba"),其中字首"ab"和兩個字尾都不匹配,但是字首"a"和字尾"a"匹配,因此,這個子串的字首字尾最長公共元素的長度為1.

讓我們再看看第四個元素,這裡我們關注的是文字串前四個字元("abab"),這個子串有3個字首("a","ab","aba")和3個字尾("b","ab","bab"),這次,子串的子串的字首字尾最長公共元素的長度為2(前字尾公有"ab").

這個例子很有趣,下面我們再看匹配表的第5個元素,此時我們關心文字串的前5個字元("ababa"),子串有4個字首("a","ab","aba","abab")和4個字尾("a","ba","aba","baba"),現在有兩對前字尾是匹配的,分別是"a"和"aba",因為後者長於前者,所以"aba"贏了,這個子串的字首字尾最長公共元素長度是3。

接下來直接來到匹配表的第7個元素,對應的文字串子串是"abababc",雖然它有好幾個字首和字尾,但是顯而易見,沒有一對前字尾是匹配的,因此該子串的字首字尾最長公共元素長度是0.

最後來看匹配表的第8個元素,對應文字串"abababca",因為第乙個和最後乙個字元都是"a",所以該文字串的字首字尾最長公共元素的長度至少是1了,對於長度大於等於2的前字尾,因為字尾包含字元 a c, 並且只有最後乙個字首"bababac"也包含a c,所以我們只需要看看長度為7的字首("bababca")和字尾("abababc")的匹配情況就行了,不巧的是,顯然二者並不匹配。所以文字串"abababca"的字首字尾最長公共元素的長度為1.

怎樣使用部分匹配表?

當我們找到部分匹配時,我們可以使用部分匹配表中的值來跳過(而不是重做不必要的舊比較)。 公式如下:

如果找到長度partial_match_length的部分匹配,並且table[partial_match_length] > 1,

我們可以跳過partial_match_length - table [partial_match_length - 1]個字元

讓我們用模式串"abababca"來匹配文字串"bacbababaabcbab",下面是模式串的部分匹配表:

第一次兩個串在這裡匹配:

部分匹配長度是1.

部分匹配表中 table[partial_match_length - 1](即table[0])為0,所以我們不能跳過任何長度,只能乙個接著乙個比較,下乙個部分匹配如下:

部分匹配的長度是5,table[partial_match_length - 1](即table[4])為3,即我們可以跳過 partial_match_length-table[partial_match_length - 1](即是5-table[4] = 5-3=2)個字元:

這時,模式串已經越界了,所以,匹配失敗。

結論

我對KMP演算法的理解

kmp演算法的核心在於失配回溯表 pnext,相比於通過逐個比較來匹配字串的樸素演算法,kmp通過對模式串的分析,可以做到比較指標在主串上不回溯,一直向前。1.kmp如何實現不回溯?對於主串 t0 t1.tj,模式串 p在 pi處與 tj 失配,假設 p0 pi 1 存在最長相等前字尾,可以證明將模...

對KMP演算法的理解

kmp演算法是一種高效的模式匹配演算法,複雜度可以達到o m n 而普通模式匹配演算法的複雜度為o m n 普通模式匹配演算法 從主串的第乙個字元 或者給定的第pos個字元 開始和子串的第乙個字元開始比較,若相等,則繼續比較後面的字元。若不相等,則從主串本次開始比較的字元的下乙個字元開始,與子串的第...

對KMP演算法的理解

kmp演算法是一種高效的模式匹配演算法,複雜度可以達到o m n 而普通模式匹配演算法的複雜度為o m n 普通模式匹配演算法 從主串的第乙個字元 或者給定的第pos個字元 開始和子串的第乙個字元開始比較,若相等,則繼續比較後面的字元。若不相等,則從主串本次開始比較的字元的下乙個字元開始,與子串的第...