文章**:
記得第一次接觸kmp演算法的時候是在初中,那個時候搞noip的競賽。直到上了高中搞noi,都一直沒有搞清楚kmp演算法的原理。現在正好有時間,可以理一理對kmp演算法的理解。
咱們首先給出kmp演算法的結論:
1.假設現在s串匹配到 i 位置,t串匹配到 j 位置
如果當前字元匹配成功,即s[i] == t[j] 令i++,j++,繼續匹配下乙個字元;
如果失配,即s[i] != t[j] 令i不變,j = next[j],(next[j] <= j - 1),即模式串t相對於原始串s向右移動了至少1位
(換言之,當匹配失敗時,模式串向右移動的位數為:失配字元所在位置 - 失配字元對應的next 值,即移動的實際位數:j-next[j] >= 1)
接下來,分別具體闡述這3個步驟。
字首字尾
如果給定乙個字串:「abcdabd」,那麼其各個字首字尾字串分別如下**所示:
也就是說,原字串對應的各個字首字尾的公共元素的最大長度表為(下簡稱最大長度表):
基於《最大長度表》匹配
下面,咱們就結合之前的最大長度表和上述結論,進行字串的匹配。給定如下圖所示的原始串和模式串
因為模式串中首尾可能會有重複的字元,故可得出下述結論:
失配時,模式串向右移動的位數為:已匹配字元數 - 失配字元的上一位字元所對應的最大長度值最大長度表引出next 陣列
由上文,我們已經知道,字串「abcdabd」各個字首字尾的最大公共元素長度分別為:
而且,根據這個表可以得出下述結論
上文利用這個表和結論進行匹配時,我們發現,當匹配到乙個字元失配時,其實沒必要考慮當前失配的字元,更何況我們每次失配時,都是看的失配字元的上一位字元對應的最大長度值。如此,便引出了next 陣列。
給定字串「abcdabd」,可求得它的next 陣列如下:
把next 陣列跟之前求得的最大長度表對比後,不難發現,next 陣列相當於「最大長度值」 整體向右移動一位,然後初始值賦為-1。意識到了這一點,你會驚呼原來next 陣列的求解竟然如此簡單!從而有
失配時,模式串向右移動的位數為:失配字元所在位置 - 失配字元對應的next 值而後,你會發現,無論是基於最大長度表的匹配,還是基於next 陣列的匹配,兩者得出來的向右移動的位數是一樣的。不信的話,咱們可以來看看具體過程。
基於《next 陣列》匹配
下面,我們來基於next 陣列進行匹配。
匹配過程一模一樣。也從側面佐證了,next 陣列確實是只要將各個最大字首字尾的公共元素的長度值右移一位,且把初值賦為-1 即可。
基於《最大長度表》與基於《next 陣列》等價
其實,利用next 陣列進行匹配失配時,模式串向右移動 j - next [ j ] 位,等價於已匹配字元數 - 失配字元的上一位字元所對應的最大長度值。為什麼呢?
j 從0開始計數,那麼當數到失配字元時,j 的數值就是已匹配的字元數;
由於next 陣列是由最大長度值表整體向右移動一位(且初值賦為-1)得到的,那麼失配字元的上一位字元所對應的最大長度值,即為當前失配字元的next 值。
那為何本文不直接利用next 陣列進行匹配呢?因為next 陣列不好求,而乙個字串的字首字尾的公共元素的最大長度值很容易求,例如若給定字串「abab」,要你求其next 陣列,則乍一看,無從求起,而要你求其字首字尾公共元素的最大長度,則很容易得出是:0 0 1 2,如下**所示:
然後這4個數字 全部整體右移一位,且初值賦為-1,即得到其next 陣列:-1 0 0 1。
演算法 KMP演算法
kmp演算法主要解決的問題就是在字串 主串 中的模式 pattern 定位問題。記主串為t,模式串為p,則kmp演算法就是返回p在t 現的具體位置,如果沒有出現則返回 1。如果 i 指標指向的字元和 j 指標指向的字元不一致,那麼把 i 右移1位,j 從0位開始,從新開始匹配 如果 i 指標指向的字...
kmp演算法next例題 KMP演算法next陣列求解
kmp演算法與bf演算法的比較 bf演算法的想法十分樸素,即先將子串t的第一位與主串s的第一位對齊開始匹配,當不能匹配時將子串整體往後移一位,然後重新匹配,以此類推直至排出結果 如當遇到下圖所示情況時,需將子串整體後移一位,將i,j分別回溯到主串第2位和子串第一位。kmp演算法 對bf進行思考後,我...
KMP及KMP改進演算法
kmp 看毛片 演算法確實很難理解,上網搜了半天想了很久才大概想明白。kmp演算法精華在於next陣列 部分匹配值 即next陣列就是 字首 和 字尾 的最長的共有元素的長度。以 abcdabd 為例,a 的字首和字尾都為空集,共有元素的長度為0 ab 的字首為 a 字尾為 b 共有元素的長度為0 ...