珠玉在前,有講解的很清晰的文章幫助讀者來理解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;
}