KMP (Knuth-Morris-Pratt) 算法以 O(m+n) 時間復雜度解決模式串在文本串中的匹配問題,核心在於利用「部分匹配」信息避免主串指針回溯,將模式串向右滑動最大可能距離。
KMP 實質是構建一個確定性有限自動機 (DFA):
next[j] 表示模式串第 j 位失配時應跳轉的狀態 (即最長公共前後綴長度)。next[0] = -1 (或 0,視實現)。對於 i > 0,已知 next[i-1] = k:
P[i] == P[k],則 next[i] = k+1。P[i] != P[k] 且 k > 0,令 k = next[k-1],重複判斷。k == 0 仍不等,next[i] = 0。
// 標準版 (0-based 索引)
void get_next(const char *P, int m, int *next) {
next[0] = -1;
int k = -1;
for (int i = 1; i < m; i++) {
while (k >= 0 && P[i] != P[k+1]) k = next[k];
if (P[i] == P[k+1]) k++;
next[i] = k;
}
}
標準版存在「多比較」問題:若 P[i] == P[next[i]],失配時會跳轉到相同字符再次比較。優化:若 P[i] == P[k] 則 next[i] = next[k],直接跳過相同字符。
void get_next_optimized(const char *P, int m, int *next) {
next[0] = -1;
int k = -1;
for (int i = 1; i < m; i++) {
while (k >= 0 && P[i] != P[k+1]) k = next[k];
if (P[i] == P[k+1]) k++;
// 優化點
if (i+1 < m && P[i+1] == P[k+1]) next[i] = next[k];
else next[i] = k;
}
}
int kmp_search(const char *S, int n, const char *P, int m, const int *next) {
int i = 0, j = 0;
while (i < n && j < m) {
if (j == -1 || S[i] == P[j]) { i++; j++; }
else j = next[j] + 1; // next 存的是索引,+1 對應狀態
}
return (j == m) ? (i - m) : -1;
}
k 只增不減,總回溯次數 ≤ m,故 O(m)。i 只增不減,j 總增加 ≤ n,總回溯 ≤ n,故 O(n)。std::search (Boyer-Moore-Horspool) 在隨機文本上常比 KMP 快,但最壞 O(mn);KMP 保證最壞線性,適合實時系統。KMP 通過「模式串自我分析」預計算 Next 數組,將匹配過程轉化為 DFA 確定性轉移,實現了理論最優的線性時間匹配。理解其「最長公共前後綴」核心邏輯,是掌握進階字符串算法 (AC 自動機、後綴自動機、Z-algorithm) 的基石。