字符串KMP算法
P3375 【模板】KMP字符串匹配
这已经是第三次学KMP啦,不知道为什么老是忘
字符串匹配算法:
最简单的是暴力搜索,但很慢
KMP算法更加快速高效:
s1:a b a a c a b a b c a c
s2:a b a b c
一.计算前缀表prefix_table
将S2单独拿出来S2:a b a b c
a //最长公共前后缀的长度为0
a b // 最长公共前后缀的长度为0
a b a //最长公共前后缀的长度为1
a b a b //最长公共前后缀的长度为2
a b a b c //最长公共前后缀的长度为0
一般情况下:会去掉最后一种情况a b a b c,将next延后一位,第一个值设为-1
S2: a b a b c
next[]:-1 0 0 1 2
二.KMP如何利用前缀表进行匹配步骤(自己匹配自己)
1.依次匹配:
2.匹配失败,转移:
for(int i=1;i<l2;i++)//自己匹配自己
{
while(j&&s2[i]!=s2[j])//如果不相等就一直找到相等为止
j=kmp[j];
kmp[i+1]=s2[j]==s2[i]?++j:0;//不相等的情况,就是无重叠,直接赋0
}
3.转移后重新匹配:
三.进行两个字符串的匹配:
1.当遇到不匹配时,就会用到kmp[]数组,转移到kmp[]数组储存的下标位:
2.进行转移重新匹配:
for(i=0;i<l1;i++)
{
while(j&&s1[i]!=s2[j]) j=kmp[j];//如果不匹配则将利用kmp数组往回跳找
j+=s1[i]==s2[j]?1:0;//如果相等匹配下一位
if(j==l2) cout<<i-l2+2<<endl;//如果匹配完一次,就输出一次初始位置
}
code:
#include <iostream>
#include <cstring>
using namespace std;
//kmp算法
const int N=1e6+10;
int kmp[N];
int l1,l2,j;
int main()
{
char s1[N],s2[N];
cin>>s1;
cin>>s2;
l1=strlen(s1);
l2=strlen(s2);
j=0;
kmp[0]=kmp[1]=0;
for(int i=1;i<l2;i++)//自己匹配自己
{
while(j&&s2[i]!=s2[j])//如果不相等就一直找到相等为止
j=kmp[j];
kmp[i+1]=s2[j]==s2[i]?++j:0;//不相等的情况,就是无重叠,直接赋0
}
j=0;
for(i=0;i<l1;i++)
{
while(j&&s1[i]!=s2[j]) j=kmp[j];//如果不匹配则将利用kmp数组往回跳找
j+=s1[i]==s2[j]?1:0;//如果相等匹配下一位
if(j==l2) cout<<i-l2+2<<endl;//如果匹配完一次,就输出一次初始位置
}
for(i=1;i<=l2;i++)
{
cout<<kmp[i]<<" ";
}
cout<<endl;
return 0;
}