关于KMP算法的重大发现

之前写KMP模板的时候,nx[i]代表最大的一个x,使s[1,x-1]是s[1,i-1]的后缀。(方法1)

然而网上还有另一种方法求nx数组,nx[i]表示最大的一个x,使s[1,x]是s[1,i]的后缀。(方法2)

两种nx数组在具体匹配的时候方法稍有不同,但都能正确匹配字符串。

但是在做字符串DP题的时候,发现网上的题解大多是利用第二种nx数组的性质进行状态的转移。

当时试着写了一下那种nx的求法,但是觉得很别扭,用不惯也记不住。

不知所措。

今天看了一下洛谷的KMP模板(P3375)(传送门),发现得求出第二种nx数组......

这回把第二种求法忘了,也很反感那么写。

于是立志要找出两种方法的联系。

很简单嘛:nx2[i]=nx1[i+1]-1

同时,getnx的时候要走到m+1(m为模式串长),这样nx[m+1]才有值。

给一个洛谷P3375的代码。

注意getnx的改动和最后要求输出nx数组的时候是怎么操作的。

 1 #include<cstdio>
 2 #include<cstring>
 3 
 4 char s1[1000005],s2[1000005];
 5 int nx[1000005];
 6 int pos[1000005],cnt;
 7 int n,m;
 8 
 9 void getnx()
10 {
11     nx[1]=0;
12     for(int i=2,j=1;i<=m+1;)
13     {
14         nx[i]=j;
15         while(j&&s2[i]!=s2[j])j=nx[j];
16         i++,j++;
17     }
18 }
19 
20 void kmp()
21 {
22     for(int i=1,j=1;i<=n;)
23     {
24         while(j&&s1[i]!=s2[j])j=nx[j];
25         if(j==m)
26         {
27             pos[++cnt]=i-m+1;
28             j=nx[j];
29         }
30         else i++,j++;
31     }
32 }
33 
34 int main()
35 {
36     scanf("%s",s1+1);
37     scanf("%s",s2+1);
38     n=strlen(s1+1);
39     m=strlen(s2+1);
40     getnx();
41     kmp();
42     for(int i=1;i<=cnt;i++)printf("%d\n",pos[i]);
43     for(int i=1;i<=m;i++)printf("%d ",nx[i+1]-1);
44     return 0;
45 }

 

posted @ 2018-09-15 16:58  cervusky  阅读(265)  评论(0编辑  收藏  举报

Contact with me