这道题给定一个字符串s,从小到大输出s中既是前缀又是后缀的子串的长度。(包括它本身)
此题非常简单,借用KMP算法的next数组,设s的长度为n,则s串本身必定满足条件。其他满足条件的子串都有个特征,就是该子串的最后一个字符肯定与s的最后一个字符相同。这正是next数组发挥作用的时候。从n - 1位既最后一位开始回滚,若s[next[n-1]] == s[n-1],则子串s[0,1,2,...,next[n-1]]是满足条件的子串。然后判断s[next[next[n-1]]] == s[n-1]是否成立,这样一直回滚,直到next[next[.....next[n-1]]] == -1为止。把答案从大到小存下来,再从小到大输出即可。
上面说得有点抽象,就如题目中的例子原串=ababcababababcabab,next=0 1 1 2 3 1 2 3 4 5 4 5 4 5 6 7 8 9 10
我们知道next【19】=10,意思也就是说你当前的字符串与原串在第19个字符不同了,你下一次跳到你要比较的字符串的第10位和原串
的第19位进行比较,根据next数组的定义,也就是说前缀的9个字符和后缀的9个是一样的所以直接让你的串的第10个和原串的19位相比较
而next【10】=5,也就是说你已经比较完了前四个,直接第五个和19位比较,下面的一致类推。
next数组想法很犀利啊……
来一串犀利的代码......
#include<stdio.h>
#include<string.h>
int next[400005];
char str[400005];
void GetNextval(){
int i=0;
int j=-1;
next[0]=-1;
int len=strlen(str);
while(i<len){
if(j==-1||str[i]==str[j]){
next[++i]=++j;
}
else j=next[j];
}
}
void Print(int i){ //递归地输出next数组的值
if(next[i]<=0)return;
Print(next[i]);
printf("%d ",next[i]);
}
int main()
{
while(scanf("%s",str)!=EOF){
GetNextval();
Print(strlen(str));
printf("%d\n",strlen(str)); //由于包括它本身,所以最后要输出它本身的长度
}
return 0;
}