KMP演算法next陣列的深入理解
之前一直對KM]P的next陣列的求法不太理解,尤其是其遞推求解過程中的k=next[k]這句話,今天看了某位博主的部落格,感覺受益匪淺,分享一下。
轉載地址:https://blog.csdn.net/starstar1992/article/details/54913261/
計算next陣列
void cal_next(char *str, int *next, int len)
{
next[0] = -1;//next[0]初始化為-1,-1表示不存在相同的最大字首和最大字尾
int k = -1;//k初始化為-1
for (int q = 1; q <= len-1; q++)
{
while (k > -1 && str[k + 1] != str[q])//如果下一個不同,那麼k就變成next[k],注意next[k]是小於k的,無論k取任何值。
{
k = next[k];//往前回溯
}
if (str[k + 1] == str[q])//如果相同,k++
{
k = k + 1;
}
next[q] = k;//這個是把算的k的值(就是相同的最大字首和最大字尾長)賦給next[q]
}
}
這個while迴圈和k=next[k]很疑惑!
確實啊,我開始看這幾行程式碼,相當懵逼,這寫的啥啊,為啥這樣寫;後來上機跑了一下,慢慢了解到為何這樣寫了。這幾行程式碼,可謂是對KMP演算法本質得了解非常清楚才能想到的。很牛逼!
直接看cal_next(..)函式:
首先我們看第一個while迴圈,它到底幹了什麼。
在此之前,我們先回到原程式。原程式裡有一個大的for()迴圈,那這個for()迴圈是幹嘛的?
這個for迴圈就是計算next[0],next[1],…next[q]…的值。
裡面最後一句next[q]=k就是說明每次迴圈結束,我們已經計算了ptr的前(q+1)個字母組成的子串的“相同的最長字首和最長字尾的長度”。(這句話前面已經解釋了!) 這個“長度”就是k。
好,到此為止,假設迴圈進行到 第 q 次,即已經計算了next[q],我們是怎麼計算next[q+1]呢?
比如我們已經知道ababab,q=4時,next[4]=2(k=2,表示該字串的前5個字母組成的子串ababa存在相同的最長字首和最長字尾的長度是3,所以k=2,next[4]=2。這個結果可以理解成我們自己觀察算的,也可以理解成程式自己算的,這不是重點,重點是程式根據目前的結果怎麼算next[5]的).,那麼對於字串ababab,我們計算next[5]的時候,此時q=5, k=2(上一步迴圈結束後的結果)。那麼我們需要比較的是str[k+1]和str[q]是否相等,其實就是str[1]和str[5]是否相等!,為啥從k+1比較呢,因為上一次迴圈中,我們已經保證了str[k]和str[q](注意這個q是上次迴圈的q)是相等的(這句話自己想想,很容易理解),所以到本次迴圈,我們直接比較str[k+1]和str[q]是否相等(這個q是本次迴圈的q)。
如果相等,那麼跳出while(),進入if(),k=k+1,接著next[q]=k。即對於ababab,我們會得出next[5]=3。 這是程式自己算的,和我們觀察的是一樣的。
如果不等,我們可以用”ababac“描述這種情況。 不等,進入while()裡面,進行k=next[k],這句話是說,在str[k + 1] != str[q]的情況下,我們往前找一個k,使str[k + 1]==str[q],是往前一個一個找呢,還是有更快的找法呢? (一個一個找必然可以,即你把 k = next[k] 換成k- -也是完全能執行的(更正:這句話不對啊,把k=next[k]換成k–是不行的,評論25樓舉了個反例)。但是程式給出了一種更快的找法,那就是 k = next[k]。 程式的意思是說,一旦str[k + 1] != str[q],即在字尾裡面找不到時,我是可以直接跳過中間一段,跑到字首裡面找,next[k]就是相同的最長字首和最長字尾的長度。所以,k=next[k]就變成,k=next[2],即k=0。此時再比較str[0+1]和str[5]是否相等,不等,則k=next[0]=-1。跳出迴圈。
相關文章
- KMP演算法中我對獲取next陣列的理解KMP演算法陣列
- kmp 演算法簡介及 next 陣列推導KMP演算法陣列
- [資料結構]KMP演算法(含next陣列詳解)資料結構KMP演算法陣列
- KMP演算法以及優化(程式碼分析以及求解next陣列和nextval陣列)KMP演算法優化陣列
- 匹配字串之——KMP演算法深入理解字串KMP演算法
- 深入理解陣列(上)陣列
- 深入理解 Java 陣列Java陣列
- 深入理解陣列-下陣列
- linux shell陣列深入學習理解Linux陣列
- POJ 2752+KMP+利用next陣列性質求出所有相同的字首和字尾KMP陣列
- 深入理解 JavaScript 物件和陣列拷貝JavaScript物件陣列
- 深入理解ES6--10.增強的陣列功能陣列
- 使用陣列來理解vue的diff演算法(一)陣列Vue演算法
- 陣列演算法-差分陣列陣列演算法
- 一文帶你入木三分地理解字串KMP演算法(next指標解法)字串KMP演算法指標
- C/C++ 二維陣列的理解(多維陣列)C++陣列
- 陣列更加深入的學習陣列
- 看圖理解基於陣列的佇列陣列佇列
- 陣列的基本演算法陣列演算法
- 深入理解 Java 列舉Java
- apply的理解和陣列降維APP陣列
- 七分鐘理解什麼是 KMP 演算法KMP演算法
- 二維陣列的指標的理解陣列指標
- 演算法-陣列與矩陣演算法陣列矩陣
- 從雜湊表(HashTable)的角度深入理解《PHP 陣列的雜湊碰撞攻擊》PHP陣列
- KMP 演算法KMP演算法
- KMP演算法KMP演算法
- 【演算法】KMP演算法演算法KMP
- 【深入淺出ES6】陣列陣列
- 演算法之KMP演算法KMP
- 深入理解React:diff 演算法React演算法
- 深入理解React Diff演算法React演算法
- Java break、continue 詳解與陣列深入解析:單維陣列和多維陣列詳細教程Java陣列
- 演算法(2)KMP演算法演算法KMP
- JavaScript 深入之類陣列物件與 argumentsJavaScript陣列物件
- 演算法基礎:動態規劃陣列中滾動陣列的使用演算法動態規劃陣列
- 看圖輕鬆理解資料結構與演算法系列(陣列)資料結構演算法陣列
- 陣列演算法 往陣列尾部新增一條資料1202陣列演算法