【POJ2752】Seek the Name, Seek the Fame-KMP思想

测试地址:Seek the Name, Seek the Fame

题目大意:多组测试数据,每组给定一个字符串S,要求求出既是S前缀又是S后缀的子串的所有可能长度。

做法:乍一看这题好像无从下手,但其实我们仔细观察这种性质,就可以发现这个过程和KMP中求next函数的过程是相似的,把S当成模式串来计算next函数,最后一个字符时特殊处理,用与计算next函数过程中寻找最大公共长度的循环相似的过程,可以看出可以取到的index的值表示除最后一个字符外的S串中,前index个字符和后index个字符是相同的,这时只要比对第index+1个字符和最后一个字符是否相等,如果相等,则index+1为一个可能的答案,与平常计算next函数的过程的唯一不同,就是验证相等后并不马上结束,而是寻找所有可能的情况,由于我们找到的答案呈降序排列,而题目要求输出升序,反过来输出即可,最后输出S串的长度即可(因为整个S串一定是它自己的前缀与后缀,并且这个值我们在前面没有能计算出来,所以需要额外输出)。

以下是本人代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
char p[400010];
int overlay[400010],ans[400010],lenp;

void calc_overlay()
{
  int index;
  overlay[0]=0;
  for(int i=1;i<lenp-1;i++)
  {
    index=overlay[i-1];
	while(index>=1&&p[index]!=p[i])
	{
	  index=overlay[index-1];
	}
	if (p[index]==p[i]) overlay[i]=index+1;
	else overlay[i]=0;
  }
}

int main()
{
  while(scanf("%s",p)!=EOF)
  {
    lenp=strlen(p);
    calc_overlay();
	if (lenp==1) {printf("1\n");continue;}
	else
	{
	  int index;
	  ans[0]=0;
	  index=overlay[lenp-2];
	  while(index>=0)
	  {
	    if (p[index]==p[lenp-1]) ans[++ans[0]]=index+1;
        if (index==0) break;
		index=overlay[index-1];
	  }
	  for(int i=ans[0];i>=1;i--) printf("%d ",ans[i]);
	  printf("%d\n",lenp);
	}
  }
  
  return 0;
}


posted @ 2016-12-17 11:58  Maxwei_wzj  阅读(111)  评论(0编辑  收藏  举报