從主串s="goodgoogle"中找到t=「google』這個子串的位置
public
static
intindex
(string s,string t)
else}if
(j>=t.length)
else
思路:
利用已經部分匹配這個有效資訊,保持i指標不回溯,通過修改j指標,讓模式串盡量地移動到有效的位置
所以,整個kmp的重點就在於當某乙個字元與主串不匹配時,我們應該知道j指標要移動到哪?
如果最前面的k個字元[0~k]和j之前的最後k個字元[j-k~j-1]是一樣的,那我們直接將j指標回溯到k的位置
為此,我們要找出指標j在最後一位時,如果失配,應該回溯到哪一位,也就是k指標的位置(k的值)
我們可以通過找出最長公共前字尾的方法來求k
如上圖,abcab的最長公共前字尾為2,所以k=2(最前面的2個字元[0~2]和j之前的最後2個字元[j-2~j-1]是一樣的,並且k指標指向第2位),當j在最後一位失配時,j應該回溯到子串第2位,也就是c的位置
然而,最長前字尾表(pmt表)並不是最後的失配查詢表(next表),因為當我們失配時,我們要查詢的是失配位前一位的最長公共前字尾
因此,我們要將pmt表整體向後移動一格,再在第0位補上-1
現在,我們再看一下如何程式設計快速求得next陣列,這部分非常繞,我檢視了許多博文,基本沒有交代的很清楚的
先上**
public
static
int[
]getnext
(string ps)
else
}return next;
}
假設子串比較指標為j,若失配要回溯到指標k的位置
先看特殊情況,子串第0位j=0時,就與父串指標i所指的位置不匹配,此時的做法與樸素演算法無異,將子串整體向前移動一格,再次從子串第0位開始與父串比較。因此,next[0] = -1,指的是父串指標i要後移一位
j = 1時,next[1] = 0(必定是0,因為只有乙個元素,沒有最長公共前字尾)
下面是最重要的:
要求j+1指標指向位置的next值,就是看j位的最大公共前字尾的長度。
求j位的最大公共前字尾的長度,則首先需要看j-1位的next值。
(1) 若j-1位的next值為0(此時k必定等於0),那麼j所在位置只需要與子串的第0位比較(因為前一位的最長公共前字尾為0,所以不可能拼湊出比1大的)
因此,此時比較p[j]與p[k]的值(p[k]是第0位):
若相等,則 j++(要賦值給j+1),k++(讓k=1),next[j] = k(j+1位的next值為1)
若不相等,則k=next[k](讓k=-1),進入下次迴圈,j++,k++,將j+1位的next值賦為0
(2) 若j-1位的next值不為0,為k(因為此時next[j] == k),則比較j指向的那一位與k指向的那一位是否相同:
若相等,則 j++(要賦值給j+1),k++(讓k=k+1),next[j] = k(j+1位的next值為k+1)
若不等,則k回溯,k = next[k]
難點!!!!!!!!!
為什麼k要等於next[k]???
因為此時,k位置與j位置失配,已經不可能找到最長的最長公共前字尾了,但是仍然有希望去找到較小的最長公共前字尾。因此,我們要回去找除了k-1與j-1相配外,還有哪一位與j-1相配,這不正是next[j]所記錄的嘛?
有了next陣列後,kmp演算法就相當簡單
public
static
intkmp
(string ts, string ps)
else}if
(j == p.length)
else
}
模式匹配 KMP演算法詳解
kmp 模式匹配演算法 include include using namespace std 計算模式串的next陣列 模式串既做主串,又做模式串,進行匹配 時間複雜度為o m m為模式串的長度 void countnext char strpattern,int len,int next els...
模式匹配的KMP演算法詳解
這種由d.e.knuth,j.h.morris和v.r.pratt同時發現的改進的模式匹配演算法簡稱為kmp演算法。大概學過資訊學的都知道,是個比較難理解的演算法,今天特把它搞個徹徹底底明明白白。注意到這是乙個改進的演算法,所以有必要把原來的模式匹配演算法拿出來,其實理解的關鍵就在這裡,一般的匹配演...
模式匹配的KMP演算法詳解
from 模式匹配的kmp演算法詳解 這種由d.e.knuth,j.h.morris和v.r.pratt同時發現的改進的模式匹配演算法簡稱為kmp演算法。大概學過資訊學的都知道,是個比較難理解的演算法,今天特把它搞個徹徹底底明明白白。注意到這是乙個改進的演算法,所以有必要把原來的模式匹配演算法拿出來...