Seek the Name, Seek the Fame POJ - 2752(KMP应用)

Stringland有一只小猫非常有名,许多夫妇跋涉到Stringland请小猫为他们的新出生的婴儿起名字,他们寻求这个名字,同时寻求名声。为了摆脱这种无聊的工作,创新的小猫制定了一个简单而奇妙的算法:

第一步、将父亲的姓名和母亲的姓名连接到一个新的字符串S.
第二步、找一个 S 的前缀-后缀串作为新生儿的名字(前缀-后缀串是S的前缀,又是S的后缀)

比如:父亲='ala',母亲='la',我们有S ='ala'+'la'='alala'。S的潜在前缀-后缀字符串是{'a','ala','alala'}。给定字符串S,你能帮助小猫编写一个程序来计算S的可能前缀-后缀字符串的长度吗?(他可能会给你的宝宝起一个名字来感谢你:)

Input

输入包含多组数据。每个测试用例包含一行字符串 S 。

S 只包含小写字母, 1<= |S| <=400000 。

Output

对于每个测试用例,按递增顺序输出一行整数,表示新宝宝名称的可能长度。

Sample Input

ababcababababcabab
aaaaa
alala
nucacm

Sample Output

2 4 9 18
1 2 3 4 5
1 3 5
6

题意是从一个字符串中找出一个子串(这个字符串也是一个子串,这个字符串既前缀,又是后缀,所以相同),要求前后缀相同的,我们要记录输出那个子串的位置,并且从小到大输出答案。

在这里我们用到了KMP next 数组,我们都已经知道了,这个next 数组就是保存 当前位置前面包括这个字符 所组成的字符串 相同前后缀最大数量,利用这个我们从最后一位的前面逐渐找前后缀相同的,然后再与这个大字符串最后一位比较,如果相同的话,就是一个答案,我们就可以利用这个性质,我们得从后往前找这个答案,我们还要判断最后的一个字符与前面的那个子串最后一位是否相同,如果相同,答案是合理的。   其实这个做法就是从后往前找,先去掉一位最后的那个字符,找出最大相同前后缀然后再与最后那一位比较,如果行的话,就是一个答案,如果不行,那就不是答案。

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<vector>
#include<string.h>
const int maxn=400005;
using namespace std;


int nex[maxn];
char s[maxn];
int len; 

void getnex(char t[])
{
	int i=0;
	int j=-1;
	nex[0]=-1;
	while(i<len)
	{
		if(j==-1||t[i]==t[j])
		{
			i++;
			j++;
			nex[i]=j;
		}
		else
			j=nex[j];
	}
	for(int i=1;i<=len;i++)
		cout<<nex[i]<<' ';
	cout<<endl; 
	
	
	
}


int main()
{
	while(scanf("%s",s)!=EOF)
	{
		vector<int>ans;
		len=strlen(s);
		getnex(s);
		
		int t=nex[len-1];
		
		while(t!=-1)
		{
			if(s[t]==s[len-1])  
				ans.push_back(t+1);
			t=nex[t];
		}
		ans.push_back(len);
		
		sort(ans.begin(),ans.end());
		for(int i=0;i<ans.size();i++)
			cout<<ans[i]<<' ';
		cout<<endl; 
		
	}
	
	return 0;
}

发布了123 篇原创文章 · 获赞 83 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/tsam123/article/details/89413699