KMP算法可以 O ( n ) O(n) O(n)的时间内实现模式串与文本串匹配,而strstr的朴素方法要 O ( n 2 ) O(n^2) O(n2)
如果要在s1中对s2匹配,先看看朴素方法:
for (int i=1; i<=strlen(s1+1); i++)
{
int flag=1;
for (int j=1,k=i; j<=strlen(s2+1); j++,k++)
{
if (s1[k]!=s2[j])
{
flag=0;
break;
}
}
if (flag==1) pos[++top]=i;
}
看一下朴素匹配算法的具体过程和可行的改进方案,如下图所示:
改进方案呼之欲出,就是求prefix-table,关于求解过程和思路,如下图所示:
给出求解prefix-table代码实现:
void get()
{
int j=0; //j代表p[i-1],即前一个最长公共前后缀的长度
for (int i=2; i<=strlen(b+1); i++)
{
while(j && b[j+1]!=b[i]) j=p[j];
if (b[j+1]==b[i]) j++;
p[i]=j;
}
}
给出具体代码:
void work()
{
int j=0; //j代表p[i-1],即前一个最长公共前后缀的长度
while(j && b[j+1]!=a[i]) j=p[j];
if (b[j+1]==a[i]) j++;
if (j==strlen(b+1))
{
pos[++top]=i-strlen(b+1)+1; //记录成功匹配的位置
j=p[j];
}
}
给出kmp的完成代码:模板题
#include<bits/stdc++.h>
#define FAST ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define INF 0x3f3f3f3f
typedef long long ll;
const int maxn = 1e6+5;
using namespace std;
int la,lb;
char a[maxn],b[maxn];
int kmp[maxn];
void get()
{
int j=0;
for (int i=2; i<=lb; i++)
{
while(j && b[j+1]!=b[i]) j=kmp[j];
if (b[j+1]==b[i]) j++;
kmp[i]=j;
}
}
void work()
{
int j=0;
for (int i=1; i<=la; i++)
{
while(j && b[j+1]!=a[i]) j=kmp[j]; //j+1表示当前位置,失配就回退
if (b[j+1]==a[i]) j++;
if (j==lb)
{
cout<<i-lb+1<<endl;
j=kmp[j];
}
}
}
int main()
{
FAST;
cin>>a+1;
cin>>b+1;
la=strlen(a+1);
lb=strlen(b+1);
get();
work();
for (int i=1; i<=lb; i++) cout<<kmp[i]<<' ';
cout<<endl;
return 0;
}