KMP-字符串
虽然我们可以根据板子题:兔子和兔子同样实现线性字符串匹配的速度。
但是也有更好的算法KMP,其更高效快捷。
先看看什么是KMP算法?
例如 S = ababccabab 与T = abacabab
我们来看next数组 ,依次S[i]与T[i]进行比较,若S[i]!= T[i]
我们只需要读取next[i]数组下的内容;例如第一次 各个前5个字符 T= aba|c|a 与S = aba|b|c中 abaca与ababc的aba匹配 但是c与b不匹配了
我们可以读取next[4] == 1, 即c下的数组;
往前匹配T[next[4]] (即T[1])是否等于 S[4] ; 很好,刚好相等;
我们继续比较接下来从T[2]开始与S[5]开始比较即可,前两位可以不再进行匹配;
如何创建NEXT数组:
如下所示:
其中(1) 为 S[I] == S[J]的情况
其中(2)就是回溯,其实本质就是,因为S[I] == S[J] 当前情况下b!=c,所以我们开始回溯,往回跑。即判断s[next[i-1]]是否等于s[i],若不是,继续回溯。
其实可以理解,当前的前缀是大括号,那么同样存在前缀中有前缀和后缀的关系,这样一直回溯。知道找到s[j = next[j-1]]==s[i]的情况 。
其中(3)前缀串--相对(2)操作的基础情况下的
附上代码
#include <iostream>
#include <string>
using namespace std;
const int N = 1e7;
int next_[N];
void get_next(string T) {
int j = 0;
next_[0] = 0;
for (int i = 1; i < T.size(); i++) {
while (j > 0 && T[i] != T[j]) {
j = next_[j - 1]; // 回溯,寻找上一个的下一个点是否为T[i]
}
if (T[i] == T[j]) {
j++;
}
next_[i] = j;
}
for (int i = 0; i < T.size(); i++) {
cout << next_[i] << " ";
}
cout << endl;
}
int KMP(string S, string T) {
int m = S.size();
int n = T.size();
int j = 0;
for (int i = 0; i < m; i++) {
while (j > 0 && S[i] != T[j]) {
j = next_[j - 1]; // 回溯
}
if (S[i] == T[j]) {
j++;
}
if (j == n) {
int ans = i - n + 1;
return ans;
}
}
}
int main() {
string text = "abacabacacabcababccabab";
string pattern = "ababccabab";
// 打印文本和模式串
cout << "Text: ";
for (char c : text) {
cout << c << " ";
}
cout << endl;
cout << "Pattern: ";
for (char c : pattern) {
cout << c << " ";
}
cout << endl;
// 计算并打印部分匹配表
cout << "Next array: ";
get_next(pattern);
// 执行KMP算法进行匹配
cout<<"res="<<KMP(text, pattern);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步