kmp演算法nexts陣列通俗化解釋

2021-10-03 07:33:39 字數 1756 閱讀 6508

最近研究了一下kmp演算法,確實很繞人,弄了兩天終於弄懂了

這裡想要採用通俗化的語言解釋一下,文章不長,希望大家能夠耐心讀完。

nexts陣列主要記錄前字尾相同的數量,比如

aba前字尾都有a,所以下一位為1。

nexts陣列找前字尾問題比較簡單,其他大佬的部落格都已經詳細論述了,我這菜雞就不在這丟人現眼了

int  i=

0,j=-1

;nexts[0]

=-1;

while

(i < m)

else

}

首先nexts陣列儲存的是前一位的相同值,nexts[0]固定為-1,便於在nexts陣列查到頭之後i++,j++為下一位賦值為0,此時的情況是無前字尾相同。

接下來是匹配失敗的過程,j = nexts[j]的情形

這裡重點解釋一下這個問題,也是nexts陣列的核心問題

首先我將j = nexts[j]分為兩類,第一類是j = nexts[j]最終回到0的情況,第二類是j = nexts[j]最終回到不為0的情況

先看第一種情況

項數 : 0 1 2 3 4 5

陣列 : 1 2 3 1 3 6

nexts:-1 0 0 0 1 0

這裡重點觀察nexts[5]的值

由於nexts陣列為找前面的最大字首,所以i = 4,j = 1

(前面i =3,j = 0時匹配成功,nexts[4] = 1)

接著演算法會接著前面的公共字首1繼續往下找,也就是比較1 2 3 1 3

中的下一位1 2與1 3是否相等,此時2與3匹配失敗,j = nexts[j]

此時最終回到i = -1的位置,i++,j++,nexts[5] = 0;

這裡j最終回到-1的根本原因是因為1 2這個陣列沒有公共的字首!!!

再看第二種情況

項數 : 0 1 2 3 4 5 6 7

陣列: 1 2 1 2 1 2 3 4

next: -1 0 0 1 2 3 4 0

這裡重點觀察nexts[7]的值,也就是重點**0~6之間的資料關係

即字串1 2 1 2 1 2 3的前字尾

在前面的1 2 1 2 1 2陣列之中,由於有共同前字尾1 2 1 2

所以此時i = 6,j = 4,重點比較1 2 1 2 1 2 3中的1 2 1 2 1與字尾1 2 1 2 3能否匹配上

前面的1 2 1 2已經比較過了,比較1與3後失配

此時j = nexts[j]的根本原因是前面的1 2 1 2有相同的前字尾1 2 1 2!!!

這裡使用數學公式說明一下,設1 2 1 2 1中的前面1 2為a,後面1 2為b,1 2 1 2 3中的前面1 2為c,後面的1 2為d

已知1 2 1 2 = 1 2 1 2,前面可以匹配成功,所以a = c,b = d

又因為通過nexts陣列可以看出前面1 2 1 2的前字尾,發現a = b

所以有a = d,此時雖然1 2 1 2 1與1 2 1 2 3失配了,但是1 2 1的1 2與1 2 3的1 2仍然能夠匹配上!!

所以找到前面的nexts後再對1 2 1中的1與1 2 3中的3比較依次

總結:通過nexts陣列的分析可以看出,其實算nexts陣列可以看作是乙個遞迴的問題,原字串失配後再通過原字串之前的匹配進行繼續比較,只是這種形式通過陣列記錄了前面的前字尾,與常規的遞迴方式不同,它的遞迴是採用陣列往前尋找的形式實現的。

將概念通俗化LR LL1

短語 每個子樹的所有葉子節點,替換為最終的 直接短語 不包含其他子樹的子樹的所有葉子節點 控制代碼 最左直接短語 素短語 至少有乙個終結符,不再包含其他素短語 最左素短語 在最左面 最左推導 每一步替換最左面的非終結符,最左面的非終結符先出現 最右推導 每一步替換最右面的非終結符,最右面的非終結符先...

對IOC概念及作用的修正(或者說通俗化)

網上有無數帖子一提到什麼是ioc,答案都是千篇一律的控制反轉,自己不建立物件,交給別人建立物件。其實真正的ioc解釋起來真的很簡單,下面直接上乙個大家每天寫幾百遍的 這是乙個entity private user user以上是我自己的 和本文章無關請忽略掉 在tempcount中建立user物件,...

KMP演算法的next 陣列通俗解釋

我們在乙個母字串中查詢乙個子字串有很多方法。kmp是一種最常見的改進演算法,它可以在匹配過程中失配的情況下,有效地多往後面跳幾個字元,加快匹配速度。當然我們可以看到這個演算法針對的是子串有對稱屬性,如果有對稱屬性,那麼就需要向前查詢是否有可以再次匹配的內容。在kmp演算法中有個陣列,叫做字首陣列,也...