珠玉在前,有讲解的很清晰的文章帮助读者来理解manchester算法是如何在线性时间内求得最长回文子串的。
http://blog.csdn.net/ggggiqnypgjg/article/details/6645824
我觉得构思比较巧妙的地方在于
1. 如何解决求长度为奇数和长度为偶数的回文串的算法的统一。
解决方法是,引入没有出现在原串里的字符,变偶长回文串为奇长回文串。
2.如何线性时间求得P[i]( 表示以i为中心拓展所得最长回文串的长度 )
解决方法:和扩展kmp里求得extand数组的方法非常类似。重点都在于如何利用已匹配的信息来减少无效的比较过程。如何找到这个可以使当前点利用的前面计算过的信息的边界值,两种算法里都没有提到(我所见到的讲义里)。还需要之后的学习中慢慢去体会。
由此可见经典的算法思想可以在求解许多不同类型的题目中得到应用和拓展。所以学习manchester算法的重点在于体会这个算法是如何推导出来的。毕竟这个算法本身的应用面并不广。
下面附上manchester算法的练习题:
hdu3068(最长回文):
http://acm.hdu.edu.cn/showproblem.php?pid=3068
【参考代码】
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=110000+100;
char str[maxn] ,T[maxn*2+50];
int p[maxn*2+50];
void get_P( int L )
{
int max_pos=0,id=0;
p[0]=0;
for( int i=1; i<L-1; i++ )
{
if( max_pos>i )
p[i]=min( p[id*2-i], max_pos-i );
else p[i]=0;
while( T[i+p[i]+1]==T[i-p[i]-1] )p[i]++;
if( i+p[i]>max_pos )
{
max_pos=i+p[i];
id=i;
}
}
}
int main()
{
while( scanf("%s",str)==1 )
{
memset( p,0,sizeof p );
int len=strlen( str );
for( int i=0; i<len;i++ )
{
T[i*2+1]=str[i];
T[i*2+2]='#';
}
T[0]='$';
T[len*2+1]='\0';
int L=strlen(T);
get_P( L );
int max_id=1,max_l=0;
for( int i=1; i<L; i++ )
{
if( p[i]*2+1>max_l )
{
max_l=p[i]*2+1;
max_id=i;
}
}
if( T[max_id+p[max_id]]=='#' ) max_l/=2;
else max_l=max_l/2+1;
printf( "%d\n",max_l );
}
return 0;
}