题目链接:https://cn.vjudge.net/contest/320014#problem/F
Sample Input
3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN
Sample Output
1
3
0
翻译:每组数据两行字符串(原串和模拟串),求原串中有多少个模拟串?
KMP算法:
对于两个串,ps:BABABABCBABABABB和p:BABABB,求ps中有多少个p,常规方法如下,p串,一位一位的往后挪
对于KMP算法:
f(l)=k:l 位失配,回溯到k。(k为:前缀和后缀的最长匹配)。
分析:用一个数组记录:模拟串的每一位失配后(失配前的每一位都是匹配的),回溯到哪一位。比如第一次模拟串的最后一位B,和原串的第5位(下标从0开始)不匹配,那么模拟串就回溯到第3位(下标从0开始),和失配位置接着比较。可以看出模拟串第3位前面的都已经和原串相匹配。
如何求数组(用next数组记录)?
i和j位上的字符是否相同:
1,不同,j=next[j](回溯到相同)
2,相同
next[i+1]=j+1;
void solve(int len)
{
int i=0,j=-1;//初始化
next[0]=-1;
while(i<len)
{
if(j<0||s[i]==s[j])
next[++i]=++j;
else
j=next[j];
}
}
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+10;
char a[N],b[N];
int net[N];
void kmp(int len)/*只是对模拟串的操作,与主串无关*/
{
net[0]=-1;
int i=0,k=-1;
while(i<len)
{
if(k<0||a[i]==a[k])
net[++i]=++k;
else
k=net[k];
}
/*for(int i=0;i<len;i++)
printf("%d ",net[i]);
printf("\n");*/
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s%s",a,b);
int len1=strlen(a);
int len2=strlen(b);
kmp(len1);//预处理出来net数组
int sum=0,i=0,k=0;
while(i<len2)
{
if(k<0||b[i]==a[k])
i++,k++;
else
k=net[k];/*回溯到k位接着比较*/
if(k==len1)
{
sum++;
k=net[k];
}
}
printf("%d\n",sum);
}
return 0;
}
重复是提高熟练度的唯一方法