前置:
嘗試去思考這樣乙個問題:給定字串s和p,詢問在字串s中,字串p出現了幾次?
設s = "aabcdedf", p = "abc";
我們先從最暴力的方法入手,不難想到去針對s的每一位去和p暴力匹配。
當 $i = 0$ 時, 字串匹配如下圖:
$s[0] == p[0]$ 則繼續向後匹配,發現 $s[1] != p[1] $,則執行 $i++$ 進行下一次匹配。
當 $i = 1$ 時,匹配如下圖
$s[0] == p[0]$ 繼續向後匹配, 直到 $s[i + strlen(p) - 1] == p[strlen(p) - 1]$ 證明匹配成功。
令 $ans++$,並且 $i++$ 進行下一次匹配。
按上述方法匹配直到字串s被遍歷一遍,輸出 $ans$ 即可。
**:
1view codeint fun(char *s, char *p)
11if (j ==strlen(p))
12 ++ans;13}
14return
ans;
15 }
設字串s的長度為 $n$ , p的長度為 $m$ ,不難計算出該暴力演算法的複雜度為 $o(nm)$,在資料量較大的時候必定超時。
kmp演算法:
kmp演算法則是對上述過程中的乙個優化,使得在每次匹配的過程中,當遇到失配的情況時,可以通過之前已經匹配的資訊優化匹配過程,而不用每次都從字串p的起始位置重新匹配。
這個優化的過程就是通過 $next$ 陣列實現的。 我們將字串s稱為文字串,將字串p成為模式串。
kmp演算法分為兩個階段:1、求模式串的 $next$ 陣列。 2、結合 $next$ 陣列進行匹配。
$next$ 陣列:$next[i]$ 的含義為:模式串第 $i$ 位與文字串適配時,下一次匹配應該從 模式串第 $next[i]$ 個位置開始匹配。
圖例:
上圖匹配過程中在 $p = 6$ 時發生失配,結合 $next$ 陣列此時我們下一次匹配的起始位置應是:
因為右移四位後,模式串中又會有乙個「ab」與文字串匹配。從而不用 $i$ 移動。
不難得出結論: $next[i]$ 為 $i$之前的模式串的最長公共前字尾的長度。
之後去求 $next$ 陣列的過程其實是模擬串自我匹配的過程
int nxt[1005view code];void get_next(char *s)
//失配則i不變, j需移動到nxt[j]的位置繼續匹配
else} }
在求得 $next$ 陣列之後,我們便可以根據 $next$ 陣列進行匹配。
int kmp(char *s, char *p)view code//失配則i不變, j移動到nxt[j]位置繼續匹配
else
//匹配成功
if (j ==lenp)
++ans;
} return
ans;
}
以上便是kmp演算法的大體內容,複雜度為 $o(n + m)$。
KMP演算法詳解
模式匹配的kmp演算法詳解 這種由d.e.knuth,j.h.morris和v.r.pratt同時發現的改進的模式匹配演算法簡稱為kmp演算法。大概學過資訊學的都知道,是個比較難理解的演算法,今天特把它搞個徹徹底底明明白白。注意到這是乙個改進的演算法,所以有必要把原來的模式匹配演算法拿出來,其實理解...
KMP演算法詳解
kmp演算法即knuth morris pratt演算法,是模式匹配的一種改進演算法,因為是名字中三人同時發現的,所以稱為kmp演算法。因為偶然接觸到有關kmp的問題,所以上網查了一下next陣列和 nextval陣列的求法,卻沒有找到,只有在csdn的資料檔案裡找到了next陣列的簡單求法 根據書...
KMP演算法詳解
相信很多人 包括自己 初識kmp演算法的時候始終是丈二和尚摸不著頭腦,要麼完全不知所云,要麼看不懂書上的解釋,要麼自己覺得好像心裡了解kmp演算法的意思,卻說不出個究竟,所謂知其然不知其所以然是也。經過七八個小時地仔細研究,終於感覺自己能說出其所以然了,又覺得資料結構書上寫得過於簡潔,不易於初學者接...