本文是介紹 什麼是 BF演算法、KMP演算法、BM演算法 三部曲之一。
KMP演算法 內部涉及到的數學原理與知識太多,本文只會對 KMP演算法 的執行過程、 部分匹配表 、next陣列 進行介紹,如果理解了這三點再去閱讀其它有關 KMP演算法 的文章肯定能有個清晰的認識。
以下的文字描述請結合視訊動畫來閱讀~
視訊地址:https://www.bilibili.com/video/av60334201/
定義
Knuth-Morris-Pratt 字串查詢演算法,簡稱為 KMP演算法,常用於在一個文字串 S 內查詢一個模式串 P 的出現位置。
這個演算法由 Donald Knuth、Vaughan Pratt、James H. Morris 三人於 1977 年聯合發表,故取這 3 人的姓氏命名此演算法。
是不是感覺 Donald Knuth 這個名字很眼熟?沒錯,在前面 這或許是講解 Knuth 洗牌演算法最好的文章 一文中也出現了他!
下面直接給出 KMP演算法 的操作流程:
- 假設現在文字串 S 匹配到 i 位置,模式串 P 匹配到 j 位置
- 如果 j = -1,或者當前字元匹配成功(即 S[i] == P[j] ),都令 i++,j++,繼續匹配下一個字元;
如果 j != -1,且當前字元匹配失敗(即 S[i] != P[j] ),則令 i 不變,j = next[j]。此舉意味著失配時,模式串 P相對於文字串 S 向右移動了 j - next [j] 位 - 換言之,將模式串 P 失配位置的 next 陣列的值對應的模式串 P 的索引位置移動到失配處
看不明白?直接看動畫!
執行過程
以下圖文字串 S 與模式串 P 為例:
首先,列出模式串 P 的所有子串:
a | |||||||
---|---|---|---|---|---|---|---|
a | b | ||||||
a | b | a | |||||
a | b | a | a | ||||
a | b | a | a | b | |||
a | b | a | a | b | c | ||
a | b | a | a | b | c | a | |
a | b | a | a | b | c | a | c |
然後,求得每一個子串的所有字首與字尾。
字首 指除了最後一個字元以外,一個字串的全部頭部組合;字尾 指除了第一個字元以外,一個字串的全部尾部組合。
以第五列為例進行演示。
字首為
a | |||
---|---|---|---|
a | b | ||
a | b | a | |
a | b | a |
字尾為
b | |||
---|---|---|---|
a | b | ||
a | A | b | |
b | a | a | b |
因此,它的字首字尾的公共元素的最大長度為 2。
求得原模式串 P 的子串對應的各個字首字尾的公共元素的 最大長度表 下圖。
根據最大長度表 去求 next 陣列:next 陣列相當於“最大長度值” 整體向右移動一位,然後初始值賦為-1。
好了,獲取了 next 陣列 後,KMP 演算法 的操作就很清晰了。
將模式串 P 與文字串 S 的字母一個個進行匹配,當失配的時候,模式串向右移動。
怎麼移動?
比如模式串的 b 與文字串的 c 失配了,找出失配處模式串的 next陣列 裡面對應的值,這裡為 0,然後將索引為 0 的位置移動到失配處。