打ACM的时候又碰到了kmp,就翻了翻以前的博客。
怎么说呢,感觉以前写的好烂啊,全是一些感性的理解,没有任何严格的证明,而且代码不是很简洁。
所以这里推荐还是看书吧,比如李煜东的《算法竞赛进阶指南》就讲的很好,而且代码写的很精炼,我觉得如果我写这篇文章的话,也只不过是把书上的话复述一遍,所以这里我就贴一个代码吧。
kmp推荐字符串从1开始标号,因为当f[i]=0的时候表示在模板串的当前位置,没有任何一个前缀能和对应的后缀匹配上,但如果从0开始标号的话就会引起歧义。
题目就是洛谷的kmp板子。
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e6 + 5;
char s[maxn], s2[maxn];
int f[maxn];
void kmp_init(char* s)
{
int n = strlen(s + 1); f[1] = 0;
for(int i = 2, j = 0; i <= n; ++i)
{
while(j && s[j + 1] != s[i]) j = f[j];
if(s[j + 1] == s[i]) ++j;
f[i] = j;
}
}
void kmp(char* t, char* p, int* f)
{
int n = strlen(t + 1), m = strlen(p + 1);
for(int i = 1, j = 0; i <= n; ++i)
{
while(j && (j == m || t[i] != p[j + 1])) j = f[j];
if(t[i] == p[j + 1]) ++j;
if(j == m) printf("%d\n", i - j + 1);
}
}
int main()
{
scanf("%s%s", s + 1, s2 + 1);
kmp_init(s2), kmp(s, s2, f);
int m = strlen(s2 + 1);
for(int i = 1; i <= m; ++i) printf("%d ", f[i]); puts("");
return 0;
}