kmp学习笔记
问题:
给定两个字符串,将两个字符串进行匹配
原理:
n^2暴力?那还要这个算法有啥用……
先看一下简便的匹配方法:
这时候我们发现在D位置是失配,如果按照暴力方式的话我们要从位置A开始继续匹配
但是由于前面一定是匹配上的,我们就可以从C开始。
对于这种失配后跳到的节点我们把它叫做当前节点的失配。(个人的理解是当前字符的前一段字符串有多长与整个字符串的前缀相等)
举个栗子:
abcdab
c
注意加红的c,我们发现,他前面的字符串'ab'与整个字符串的前缀'ab'相等,且长度为二,那么c的失配就是2。(因为如果匹配到c,那么带匹配的字符串匹当前配到的字符的前两位一定是'ab'要不然已经跳回到前面去了,所以下次匹配是只要从2号开始就行了)
实现:
因为每个字符的失配取决于它的前一个节点,可以递推。时间复杂度:O(n)
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
using namespace std;
const int max_s = 100001;
char s[max_s], ori[max_s];
int fail[max_s];
inline void make_fail()
{
int len=strlen(s);
fail[0]=-1;
for(int i=0; i<len; ++i)
{
int j=fail[i];
while(j!=-1 && s[j]!=s[i])
j=fail[j];
fail[i+1]=++j;
}
}
inline void kmp()
{
int lens=strlen(ori),len=strlen(s);
int j=0;
for(int i=0; i<lens; ++i)
{
while(j!=-1 && s[j]!=ori[i]) j=fail[j];
j++;
if(j==len) printf("get\n"),j=fail[j];
}
}
int main()
{
scanf("%s%s", ori, s);
make_fail();
kmp();
for(int i=0; i<strlen(s); ++i)
printf("%d ",fail[i]);
return 0;
}