Poj3974 最长回文子串

 

 题目链接:http://poj.org/problem?id=3974

 

最长回文子串问题,有一个O(n)的算法叫Manacher,

 

http://zhuhongcheng.wordpress.com/2009/08/02/a-simple-linear-time-algorithm-for-finding-longest-palindrome-sub-string/

原文:

Given a string S, we are to find the longest sub-string s of S such that the reverse of s is exactly the same as s.
First insert a special character ‘#’ between each pair of adjacent characters of S, in front of S and at the back of S. After that, we only need to check palindrome sub-strings of odd length.
Let P[i] be the largest integer d such that S[i-d,...,i+d] is a palindrome.  We calculate all P[i]s from left to right. When calculating P[i], we have to compare S[i+1] with S[i-1], S[i+2] with S[i-2] and so on. A comparison is successful if two characters are the same, otherwise it is unsuccessful. In fact, we can possibly skip some unnecessary comparisons utilizing the previously calculated P[i]s.
Assume P[a]+a=max{ P[j]+j :  j<i }. If P[a]+a >= i, then we have
P[i] >= min{ P[2*a-i],  2*a-i-(a- P[a])}
.
Is it the algorithm linear time? The answer is yes.
First the overall number of unsuccessful comparisons is obviously at most N.
A more careful analysis show that S[i] would never be compared successfully with any S[j](j<i) after its first time successful comparison with some S[k] (k<i).
So the number of overall comparisons is a most 2N

 

Here is a simple example, for string “a#b#a#a#b#a”. Hope it will help you.
At position #0: P[0]=0, the longest palindrome is “a”.
At position #1: max of {P[0]+0} is 0, so we just check the “a#b” to determine P[1]. It turns out that P[1]=0
At position #2: max of { P[0]+0, P[1]+1} is P[1]+1=1, so we just check “#b#”,”a#b#a” to determine P[1]. It turns out that P[2]=2.
At position #3: max of { P[0]+0,P[1]+1,P[2]+2} is P[2]+2=4. We can know that p[3]>=Min{ P[2*2-3], 2*2-3-(2-P[2]) } = 0, so we check “b#a” to determine that P[3]=0
At position #4: max of { P[0]+0,P[1]+1,P[2]+2,P[3]+3} is P[2]+2=4. So P[4]>=Min{ P[2*2-4], 2*2-4-(2-P[2]) } = 0, we check “#a#” to determine that P[4]=1
At postion #5: max of { P[0]+0,P[1]+1,P[2]+2,P[3]+3, P[4]+4} is P[4]+4=5, so P[5]>=Min{P[2*4-5], 2*4-5-(4-P[4]) }=0, we check “a#a”,…,”a#b#a#a#b#a” to determine that P[5]=5.
At position #6: max of {P[0]+0,P[1]+1,P[2]+2,P[3]+3, P[4]+4, P[5]+5} is P[5]+5=10, so P[6]>=Min{ P[2*5-6], 2*5-6-(5-P[5])} =1, we check “a#a#b” to determine that P[6]=1. (here we don’t need to check “#a#”)
At position #7: max of {P[0]+0,P[1]+1,P[2]+2,P[3]+3, P[4]+4, P[5]+5,P[6]+6} is P[5]+5=10, so P[7]>=Min{ P[2*5-7], 2*5-7-(5-P[5]) }=0, we check “a#b” to determine that P[7]=0.
At position #8: max of {P[0]+0,P[1]+1,P[2]+2,P[3]+3, P[4]+4, P[5]+5,P[6]+6,…} is P[5]+5=10, so P[8]>=Min{ P[2*5-8], 2*5-8-(5-P[5])} =2,
we don’t need check any substring due to the boundary.

Code:

#include<stdio.h>
#include<string.h>

#define M 1000008

char o[M],s[M<<1];
int p[M<<1];
int r;

int MMin(int a,int b)
{
	return a>b?b:a;
}

void Manacher()
{
	int i,j,max;
	int n=strlen(o);
	memset(s,'#',sizeof(s));

	for(i=0;i<n;i++)
		s[(i+1)<<1]=o[i];
	s[n=(n+1)<<1]=0;
	r=max=0;
	for(i=0;i<n;i++){
		if(max>i) p[i]=MMin(p[2*j-i],max-i);

		else p[i]=1;

		while(s[i+p[i]]==s[i-p[i]]) 

			p[i]++;

		if(p[i]>r) r=p[i];

		if(i+p[i]>max)
			max=i+p[i],j=i;
	}
}
int main()
{
	int t=0;

	while(~scanf("%s",o),o[0]^'E'){
		Manacher();
		printf("Case %d: %d\n",++t,r-1);
	}

	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值