原文来自某位大佬,链接后补
#include <iostream>
#include <vector>
using namespace std;
//KMP算法: 每次失配,S串的索引i不动,P串的索引j定位到某个数。T(n)=O(n+m),时间效率明显提高
vector<int> getNext(string p) { //获取跳跃位,移动长度取决于公共元素长度
int n = p.size(), k = -1, j = 0; //k 的值-1~~6 ,不会超过p.size()
vector<int> next(n, -1); //存放于容器vector中,0位存了-1,-1表示不存在相同的最大前缀和最大后缀
while (j < n - 1) {
if (k == -1 || p[j] == p[k]) { //如果下一个不同,那么k就变成next[k],注意next[k]是小于k的,无论k取任何值。
++k; ++j; //此处 k 的值是从0开始的,匹配成功,继续匹配下一个字符
//较之前next数组求法,改动在下面4行
if (p[j] != p[k])
next[j] = k; //之前只有这一行 此处k 的值就是前后缀公共元素的长度
else
next[j] = next[k]; //p[j] == p[k]
} else {
k = next[k]; //往前回溯
}
}
return next; //匹配完成,获得所有 跳跃位/匹配值 /next里存的是前后缀公共元素的长度
}
int kmp(string s, string p) { //s 为主串,p 为模式串
int m = s.size(), n = p.size(), i = 0, j = 0; //从首位开始匹配
vector<int> next = getNext(p); //定义容器next ,传参并获取getNext :-1,0,0,0,-1,0,2
while (i < m && j < n) { //主串和模式串都在长度范围内匹配
if (j == - 1 || s[i] == p[j]) { //模式串下标为-1||匹配成功时
++i; ++j; //匹配下一位
} else { //否则
j = next[j]; //
}
}
return (j == n) ? i - j : -1; //匹配结束,返回匹配结果;成功返回下标i-j,失败-1
}
int main() {
cout << kmp("BBC_ABCDAB_ABCDABCDABDE", "ABCDABD") << endl; // kmp传入主串,模式串,然后输出结果
//Output: 15
}
kmp算法
最新推荐文章于 2023-04-09 17:43:52 发布