关于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 }