天天看点

poj3974 Palindrome [字符串回文]

本题的题意是给你一个字符串 让你判断这个字符串中最长的回文子串的长度

嗯 这题可以用O(n)的时间复杂度的manacher算法来处理

manacher在很久前就知道了,但是只是知道了怎么去构造但是还没没有明白怎么去更新

嗯 大概就是这样的情况 嗯所以 看了人家的博客点击打开链接 写的非常的明白

首先我们先在原来的字符串中插入不用到的字符形如  abcd -> #a#b#c#d#

这样做了之后就可以将奇数个长的回文串和偶数长的回文串整合起来了

主要考虑怎么去计算dp[i](dp[i] 表示以i为中心的字符串能构成多长的回文串)

考虑下面两种情况

1)i 不在以i之前的点为中心的回文串所包含

那么就需要哦从i开始向外判断回文

2)i在之前的点位中心的回文串所包含 假设这个中心点为l k为i-l

那么更具回文串的性质 l+k(i)位置的点 和 l-k的位置 的情况一样的

poj3974 Palindrome [字符串回文]

在2)的条件下会有上述的三种情况

情况一:这种情况比较的简单 dp[i]=dp[l-k];

情况二:这种情况要想明白 很显然不可能在i处出现对应到最长的回文串外的如果能够出去表示最长回文串的长度仍能增加 这和我们的定义不符

所以在情况二中的dp[i]=dp[l]+l-i;

情况三就是说我们i对应的位置能够扩展到最长回文串的边缘 这个时候我们就需要继续的向外扩展找能否有更长的回文串

#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
char s[2000100];
int dp[2000100];
int main(){
	int cas=1;
	while(~scanf("%s",&s)){
		if(s[0]=='E') break;
		int len=strlen(s);
		for(int i=len;i>=0;i--){
			s[i+i+2]=s[i];
			s[i+i+1]='#';
		}
		s[0]='.';
		len=strlen(s);
		int l=0,ans=0;
		dp[0]=1;
		for(int i=1;i<len;i++){
			if(l+dp[l]<=i){
				dp[i]=1;
				int k=1;
				while(s[i+k]==s[i-k]) k++,dp[i]++;
			}else{
				int k=i-l;
				dp[i]=dp[l-k];
				if(i+dp[i]>l+dp[l])dp[i]=dp[l]+l-i;
				k=dp[i];
				while(s[i+k]==s[i-k]) k++,dp[i]++;
			}
			if(l+dp[l]<i+dp[i])  l=i;
			ans=max(ans,dp[i]-1);		
		}
		printf("Case %d: %d\n",cas++,ans);
	//	printf("%d\n",ans);
	}
}