本文实现一个KMP 算法案例,用于字符串匹配。KMP 算法通过预处理模式串,避免在匹配过程中重复比较字符,从而提高效率。
问题描述
给定一个文本串 text
和一个模式串 pattern
,如何高效地在文本串中查找模式串的所有出现位置?
算法思想
KMP 算法的核心思想是利用部分匹配表(Partial Match Table, PMT),也称为 next
数组,来跳过不必要的比较。具体步骤如下:
- 预处理模式串,生成
next
数组。next[i]
表示模式串的前i
个字符中,最长的相同前缀和后缀的长度。 - 在匹配过程中,当字符不匹配时,利用
next
数组跳过部分字符,避免从头开始比较。
C++代码实现
#include <iostream>
#include <vector>
using namespace std;
// 生成 next 数组
vector<int> computeNext(const string& pattern) {
int n = pattern.size();
vector<int> next(n, 0);
int len = 0; // 当前最长相同前缀后缀的长度
for (int i = 1; i < n; i++) {
while (len > 0 && pattern[i] != pattern[len]) {
len = next[len - 1];
}
if (pattern[i] == pattern[len]) {
len++;
}
next[i] = len;
}
return next;
}
// KMP 算法实现
void kmpSearch(const string& text, const string& pattern) {
int n = text.size();
int m = pattern.size();
vector<int> next = computeNext(pattern);
int i = 0, j = 0; // i 是文本串的索引,j 是模式串的索引
while (i < n) {
if (text[i] == pattern[j]) {
i++;
j++;
if (j == m) {
cout << "模式串出现在位置: " << i - m << endl;
j = next[j - 1]; // 继续匹配下一个
}
} else {
if (j > 0) {
j = next[j - 1];
} else {
i++;
}
}
}
}
int main() {
string text = "ABABDABACDABABCABAB";
string pattern = "ABABCABAB";
cout << "文本串: " << text << endl;
cout << "模式串: " << pattern << endl;
kmpSearch(text, pattern);
return 0;
}
关键解析
- 时间复杂度:
O(n + m)
,其中n
是文本串长度,m
是模式串长度。 - 空间复杂度:
O(m)
,用于存储next
数组。 - 适用场景:
- 高效的字符串匹配。
- 处理大规模文本串和模式串。
输出示例
文本串: ABABDABACDABABCABAB
模式串: ABABCABAB
模式串出现在位置: 10
总结
KMP 算法是一种高效的字符串匹配算法,通过预处理模式串生成 next
数组,避免了不必要的字符比较。