最近研究了一下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演算法中有個陣列,叫做字首陣列,也...