其实这道题用KMP的next[]也挺方便的,用扩展的KMP更好理解一点。
(1)用KMP的next[]:
求出next[]函数之后,length是最长的,也就是本身,next[lenth]是次长的,next[next[length]]又次之。。。
直到next[]为-1为止。这样得到的序列正好是降序的,反着输出来就ok了。
为什么这么做?由next函数特性,好好想一下,肯定就很容易明白了。或者自己举个例子,把它的next[]求出来,看一下就明白了。
(2)扩展的KMP
扩展的KMP是求得前缀。next[i]表示从i到length,与0到length的最长的匹配。
(哎呀,我这里就不啰嗦它了,不知道的,说了也没用,知道的,我这一说就明白了。)
我这里给一个讲解扩展的KMP链接,有兴趣的可以看看:
http://www.cnblogs.com/yefeng1627/archive/2012/12/24/2830979.html
求出next之后,判断next[i]==length-i,就是前后缀匹配的长度。
所以i=length-1到i==0,逆着输出出来就ok了。
我是用第二中方案做的,代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX = 400011;
int next[MAX],extand[MAX];
char ch[MAX];
void getnext(char *T){// next[i]: 以第i位置开始的子串 与 T的公共前缀
int i,length = strlen(T);
next[0] = length;
for(i = 0;i<length-1 && T[i]==T[i+1]; i++);
next[1] = i;
int a = 1;
for(int k = 2; k < length; k++){
int p = a+next[a]-1, L = next[k-a];
if( (k-1)+L >= p ){
int j = (p-k+1)>0? (p-k+1) : 0;
while(k+j<length && T[k+j]==T[j]) j++;// 枚举(p+1,length) 与(p-k+1,length) 区间比较
next[k] = j, a = k;
}
else next[k] = L;
}
}
int main()
{
int i,j;
while(scanf("%s",ch)!=EOF)
{
getnext(ch);
int length=strlen(ch);
for(i=length-1;i>=0;i--)
{
if(next[i]==length-i)
printf("%d ",next[i]);
}
printf("\n");
}
return 0;
}