前言
KMP算法是一种改进后的字符串匹配算法,即在一个字符串中定位另一个串的高效算法。通过辅助数组实现跳过扫描不必要的目标字符串,以达到优化效果。
思路
KMP有两个难点:
取最长公共前后缀.
和如何利用最长公共前后缀所反映的有效信息避免不必要的检测
最长公共前后缀匹配
字符串s1:ABABCA,求最长公共前后缀,我们只能找到最前面和最后面的两个A.
字符串s2:为ABABCAB,求最长公共前后缀,我们只需要在s1的基础上,检测那个字母是不是B即可.如果是B那么就在s1的基础上加1,如果不是那就为0
inline void GetNext()
{
int i=0,j=-1,len=strlen(s);
next[i]=j;
while(i<len){
while(j!=-1&&s[i]!=s[j]) j=next[j];
next[++i]=++j;
}
}
如何检测移动
s:ABABCA,如果s[0]与主串不匹配,那么j就为-1,通过下面的代码j++,使之为0,也就是向后移1位.
如果a[i]==s[j],就是继续匹配。如果不相等,那么next[j]号位移动到与主串当前位比较
int KmpIndex()
{
GetNext();
int i=0,j=0,lena=strlen(a),lens=strlen(s);
while(i<lena&&j<lens){
while(j!=-1&&a[i]!=s[j]) j=next[j];
i++,j++;
}
if(j==lens) return i-lens;//模式串在主串中首次出现的位置
else return -1;
}
int KmpCount()
{
GetNext();
int i=0,j=0,ans=0,lena=strlen(a),lens=strlen(s);
while(i<lena){
while(j!=-1&&a[i]!=s[j]) j=next[j];
i++,j++;
if(j==lens) ans++;
}
return ans;
}
模板题
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=1e4+10;
const int M=1e6+10;
int t;
char a[M],s[N];//a主串
int next[N];
inline void GetNext()
{
int i=0,j=-1,len=strlen(s);
next[i]=j;
while(i<len){
while(j!=-1&&s[i]!=s[j]) j=next[j];
next[++i]=++j;
}
}
int KmpCount()
{
GetNext();
int i=0,j=0,ans=0,lena=strlen(a),lens=strlen(s);
while(i<lena){
while(j!=-1&&a[i]!=s[j]) j=next[j];
i++,j++;
if(j==lens) ans++;
}
return ans;
}
int main()
{
scanf("%d",&t);
while(t--){
scanf("%s",s);
scanf("%s",a);
printf("%d\n",KmpCount());
}
}