KMP算法的next/nextval值的個人理解
本文於2020.3.30.23:48重新編輯,之前看過的朋友們,你們看到並非完全正確的方法,非常抱歉!如果再次點開這篇博客,還請您重新閱讀一次,感謝!
之前學習KMP算法的時候對於next/nextval值的計算總是處在似懂非懂的狀態,后面結合了老師的方法和網上的資料自己總結了一下,下面是我自己的一些個人經驗,比較淺顯易懂,希望能幫到一部分人。
KMP算法的運行模式
KMP算法與BF算法的最大區別就是,BF算法每次匹配時模式串都是往下一位移動,又重新從模式串的第一位開始比對;而KMP算法的思想是,如果已有一部分字段匹配成功,在這一部分字段中尋找相同的兩部分小字段,即概念中的子串,以減少比較次數,提升算法效率。
但是,
這兩部分相同的子串,是有約束條件的。
計算next與nextval值
我們以串測試中的第7題為例,以下方法計算得的next與nextval值均遵循考試規則,可能不同教材有所不同。
注意:務必看完整個過程,切勿心急
在我們計算之前,要先知道next值的作用是什么。
實際上主串第i個字符與模式串某個字符不匹配后,有兩種不同的情況處理:
1.下次比較拿主串第i+1個字符與模式串第1個字符匹配;
2.下次比較依舊拿主串第i個字符與模式串的某個字符比較。
而next值的使用場景為:在KMP算法中,當主串與模式串逐個字符比較時,某個字符不匹配時,則模式串向右移動,移動的位數為next值+1。
首先next[0]的值固定為-1,而next[1]的值固定為0(關於這點后面會有解釋)
從第j=2開始,看前面的字段有無兩段相同的子串。此時前面字段為底色黃色的ab字段(以下情況的前面字段均以黃底標出)
很明顯沒有相同字段,故next[2]的值為0。這也能解釋為什么t[1]的next值一定為0,畢竟t[1]前僅有t[0]一個數,根本不可能存在兩段相同的子串,所以t[1]的next值必定為0。
j=3時同樣在前面字段中沒有兩段相同字段,不再贅述。
當j=4時,如下圖
可以看出前面字段abca中有兩段相同的子串a,用紅字標出,故相同字段的長度為1,則next值為1。(以下相同字段均以紅字標出)
繼續向下,當j=5時,情況與j=4相同。
當j=6時,如下圖
可以看出此時前面字段中相同子串為ab,故相同字段長度為2,next值為2。
接下來,當j=7時
可以看出此時前面字段中沒有相同子串,故相同字段長度為0,next值為0。但是,有些朋友看到這里會說,如果單純找前面字段中的相同子串,那像剛剛j=6時的ab字段在這里也符合標准,為什么next值不為2呢?或者,像下面這張圖片一樣,為什么next值也不是1呢?
前綴子串和后綴子串
還記得上文提到的有約束條件的子串嗎?
這便是前綴子串與后綴子串
前面的子串,叫前綴子串;同理,后面的子串,叫后綴子串
但關鍵在於,約束條件是什么呢?
讓我們再觀察一下剛剛那些沒有問題的子串,也就是前綴子串和后綴子串
上面兩張圖中前綴子串和后綴子串有什么共同點呢?
可以發現,前綴子串的第一位均為t[0]
若將此時j的值設為x,后綴子串的最后一位均為t[x-1]
用圖形來理解,就是在黃底區域中,前綴子串的第一位必須是黃底區域的第一位,即t[0];
同樣的,后綴子串的最后一位必須是黃底區域的最后一位,即t[x-1]
讓我們回到j=7的情況中,在了解了前綴子串與后綴子串的定義之后,現在的你理解為什么next[7]=0了嗎?
如果你理解了,那么恭喜你,真正掌握了next值的求算方法
觀察模式串中的前綴子串和后綴子串,判斷出的next值就是准確的。多加練習,就能很快求出next值。下面是完整的表圖,大家可以對照着再練習一遍。
nextval值的求解
當你對next值的求解駕輕就熟之后,nextval值的求解相比之下就簡單很多,除了nextval[0]的值仍為-1,其他nextval值都遵循以下規則:
不同則同,同則等於
這是什么意思呢?
下面是題7的nextval值表
注意:上表為正確的表,下面例子中的表格中的j=7一欄中的next及nextval值錯誤,請以上圖為准練習
我已經標出了所有數的nextval值,接下來讓我們看幾個例子:
當j=1時
t[1]=b,next[1]=0,則我們根據next[1]=0找到t[0]=a,a與b不同,則nextval[1]=next[1]=0,這就是不同則同
當j=2時
t[2]=c,next[2]=0,則我們根據next[2]=0找到t[0]=a,a與c不同,則nextval[2]=next[2]=0
當j=3時
t[3]=a,next[3]=0,則我們根據next[3]=0找到t[0]=a,a與a相同,則nextval[3]=nextval[0]=-1,這就是同則相等,即兩字符相同時兩者的nextval值相等
接下來的nextval值判斷同樣遵循以上方法,大家可以自己試着練習一下
注意:第一個表為正確的表,例子中的表格中的j=7一欄中的next及nextval值錯誤,請以第一個圖為准練習