您的位置:首页 > 其它

KMP算法

2017-01-02 19:01 155 查看

2017.01.02

洛谷3375:

#include<cstdio>
#include<cstring>
int l1,l2,i,j;
char a[1000001];
char b[1001];
int next[1001];
int main()
{
scanf("%s%s",a+1,b+1);
l1=strlen(a+1),l2=strlen(b+1);
j=0;
for(i=2;i<=l2;i++)
{
while(j&&b[i]!=b[j+1]) j=next[j];
if(b[i]==b[j+1]) j++;
next[i]=j;
}
j=0;
for(i=1;i<=l1;i++)
{
while(j&&a[i]!=b[j+1]) j=next[j];
if(a[i]==b[j+1]) j++;
if(j==l2)
{
printf("%d\n",i-l2+1);
j=next[j];
}
}
for(i=1;i<=l2;i++)
printf("%d ",next[i]);
return 0;
}


为什么呢?

首先第一个for循环,在需要匹配的字符串b内进行自身匹配。

①while循环 寻找第一次出现的能和字符串b内前j-1位匹配的和b[j]相同的字符的位置。

②如果不是由于j=0导致while中断则匹配位数+1,并赋给next数组。

第二个for循环长得和第一个很像,就是将字符串a与字符串b匹配。

第三个for:输出next数组。(只因luogu要输出)

end.

至于为什么要叫next数组?我也不知道。其实next中存储的是能和之前前缀字符串匹配的第一个字符出现的位置,个人认为叫做prev可能更容易理解。

2017.01.22(续):

今天上午gty学长给我们讲了KMP。

KMP大致有两个过程:

①计算失配函数

②字符串比较

以poj3461为例:传送门

题目简介:给定多对字符串,求第一个字符串在第二个字符串里出现的次数。



计算失配函数时,字符串第0位的函数值设为-1,便于以后程序的执行。

接下来从0~strlen(a)-1,依次计算下一位的函数值(包括字符串最后’\0’)。



求解f[i+1]时,由于f[i]已经求出,即图中斜线部分代表的子串相同。

若a[j]=a[i],则j即为i+1的函数值;

若a[j]≠a[i],则j=f[j],由于f[f[i]]已经求出,即图中红色等号部分代表的字串相同(图上方的f[j]等为f[j]代表的相等字符串区间),若此时a[j]=a[i],则此时的j为i+1的函数值,以此类推,直至求出或j=-1(到达字符串的第0位)。



字符串比较(中心部分)

与①类似但稍有不同,不细讲了。

详见代码:

#include<cstdio>
#include<cstring>
char a[1000010];
char b[1000010];
int f[1000010];
int n,i;
inline void makefail()
{
int j,len=strlen(a);
f[0]=-1;
for(int i=0;i<len;i++)
{
j=f[i];
while(j!=-1&&a[j]!=a[i]) j=f[j];
f[i+1]=++j;
}
}
inline int kmp()
{
int j=0,lena=strlen(a),lenb=strlen(b),ans=0;
for(int i=0;i<lenb;i++)
{
while(j!=-1&&a[j]!=b[i]) j=f[j];
j++;
if(j==lena)
{
ans++;
j=f[j];
}
}
return ans;
}
int main()
{
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%s%s",a,b);
makefail();
printf("%d\n",kmp());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  kmp 算法