KMP演算法(程式碼+圖解證明)
阿新 • • 發佈:2019-02-19
KMP演算法用於字串匹配,是相較於樸素字串匹配。所謂樸素字串匹配就是從頭到尾開始一個位置一個位置匹配,當前位置匹配失敗則會從下一個位置開始繼續匹配。
KMP演算法則是可以跳,能往前跳多遠就往前跳多遠。我們知道演算法儘量要簡化計算、去冗餘、記憶搜尋。KMP就是利用了去冗餘的思想往前跳到某一位置繼續匹配。而中間未匹配的絲毫不會有影響,這要歸結於我們next陣列的定義。
所謂next陣列中next[i]就是記錄如果當前位置位置不匹配,字串可以往前跳多遠進行重新匹配。所以next[i]就是計算i之前字串的最大回文長度(就是字首和字尾相等的最大長度)。中間跳躍的點都是不用匹配的點,這個可以證明。
如圖,我們中間跳過的位置,如果存在有用的,即b'>b的長度。這種情況反證了我們b計算錯誤,也即我們next陣列沒求最長的,也就是沒求對。故而,跳過的就是沒用的。
那麼指導跳躍的next陣列的求法如下圖所示。
上圖演示的是next[i]這一位的計算方法,使用到了遞迴。這些說明白了,直接上程式碼。
#include<iostream> #include<string> using namespace std; int * getNextArray(string ms) { if (ms.length() == 1) { int *a=new int[1]; a[0]=-1; return a; } int* next = new int[ms.length()]; next[0] = -1; next[1] = 0; int pos = 2; int cn = 0; while (pos < ms.length()) { //next陣列從2之後大於等於0 if (ms[pos - 1] == ms[cn]) { next[pos++] = ++cn; } else if (cn > 0) { cn = next[cn]; } else { next[pos++] = 0; } } return next; } //s是原串,m是模式串 int getIndexOf(string s, string m) { if (s == "" || m == "" || m.length() < 1 || s.length() < m.length()) { return -1; } int si = 0; int mi = 0; int* next = getNextArray(m); while (si < s.length() && mi < m.length()) { if (s[si] == m[mi]) { si++; mi++; } else if (next[mi] == -1) { si++; } else { mi = next[mi]; } } return mi == m.length() ? si - mi : -1; }
KMP演算法其實不難,仔細研究下就可以理解了。