大牛的好文 http://www.cnblogs.com/tangzhengyue/p/4315393.html
下图摘自链接大牛的博客
1.由"next[j] == k;"这个条件,我们可以得到A1子串 == A2子串(根据next数组的定义,前后缀那个)。
2.由"next[k] == 绿色色块所在的索引;"这个条件,我们可以得到B1子串 == B2子串。
3.由"next[绿色色块所在的索引] == 黄色色块所在的索引;"这个条件,我们可以得到C1子串 == C2子串。
4.由1和2(A1 == A2,B1 == B2)可以得到B1 == B2 == B3。
5.由2和3(B1 == B2, C1 == C2)可以得到C1 == C2 == C3。
6.B2 == B3可以得到C3 == C4 == C1 == C2
以下本菜的理解求next[]
2b青年的说法;先去匹配,如果失败,可能失败的前一部分长度的字符串的前缀和后缀相同,那就可以直接把前缀移到后缀那一块,省去了很多没用的时间。
关键就是求next数组。根据递归的思想;
next[0]=-1;
next[j]=k;p[0...k-1]=p[j-k...j-1];
1.如果p[j]==p[k],p[0...k]=p[j-k...j];next[j+1]=next[j]+1=k+1;
2.如果p[j]!=p[k],由于之前的都求了next[],所以直接移到,即匹配失败的时候,k=next[k]。
int kmp(char *s,char *p) { int i,j,len=strlen(s); i=0; j=0; getnext(p); while(i<len) { if(j==-1||s[i]==p[j]) { i++; j++; } else { j=next[j]; } if(j==strlen(p)) { return i-strlen(p); } } return -1; }//kmp匹配部分 void getnext(char *p) { int k,j,len=strlen(p); next[0]=-1; j=0; k=-1; while(j<len) { if(k==-1||p[j]==p[k]) { j++; k++; next[j]=k; } else k=next[k]; } }//递归思想求next
做了几题题目后理解的next的意思:
next 数组各值的含义:代表当前字符之前的字符串中,有多大长度的相同前缀后缀。例如如果next [j] = k,
代表j 之前的字符串中有最大长度为k 的相同前缀后缀。也就是说当前字符前的k个字符是一定相同的,但是
s[j]不一定和s[k]相同。
next数组关于循环节几个小应用
(1)i - next[i] 最小循环节(第一个字母开始),循环节的长度
(2)next[i] 最大循环节中的第几位数(此时循环节可交叉)
(3)next[i] != 0 && i % (i - next[i]) == 0,当前是循环节中的最后一位。
(4)在(3)的前提下 i / (i - next[i]) 表示的最大周期个数,也就是在最小循环节的前提下的最大周期个数。