Manacher算法是解决求给定字符串中的最长回文串问题的,时间复杂度为O(N)。
首先给出一篇很好的文章:A simple linear time algorithm for finding the longest palindrome substring
不过上面这篇文章是英文的,对于英文不好的朋友,可以看这里:O(N)回文串算法
算法比较容易理解,下面就贴个模板吧,另外还有两个例题:HDU_3068 、 Ural_1297
Manacher模板:
/*
str : 原字符数组,在每两个相邻的字符之间加入了一个‘#’(第一个之前
和最后一个之后也要加一个'#'),同时为了避免(1)处产生数组越
界,在最开始加入一个'$',在最后加入一个0 ;
P : 辅助数组,P[i]表示以i为中心,向右最多可以“走出”多少个字符,
( P[i] - 1 ) * 2 + 1 就是以i为中心的回文串的长度;
a : a = max{ a+P[a] > j + P[j] | j < i } ;
mx : mx = a + P[a] ; 以a为中心的回文串为:str[ a-P[a]+1 ....... a+P[a]-1 ]
*/
void solve(){
int mx , a , i , j , ans = 2 ;
P[0] = 1 ; a = 0 ; mx = 1 ;
rep(i , 1 , len){
if(i < mx){
P[i] = MIN( P[2*a-i] , P[a]+a-i ) ;
}
else{
P[i] = 1 ;
}
for( ; str[i+P[i]]==str[i-P[i]] ; ){ //(1)
P[i]++ ;
}
if( i + P[i] > mx ){
mx =i + P[i];
a = i ;
}
}
rep(i , 0 , len) checkmax( ans , P[i] ) ;
printf("%d\n",ans-1);
}
HDU_3068 :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#include <list>
#include <ctime>
#include <sstream>
#define rep(i,initial,end) for(i=(initial);i<(end);i++)
#define MAX(x,y) ((x)<(y)?(y):(x))
#define MIN(x,y) ((x)<(y)?(x):(y))
#define SZ(a) (sizeof(a))
#define MEM(a) ( memset((a) , 0 , sizeof(a)) )
#define MEME(a) ( memset((a) , -1 , sizeof(a)) )
#define MEMX(a) ( memset((a) , 0x3f , sizeof(a)) )
using namespace std;
typedef long long LL ;
typedef unsigned long long ULL ;
typedef unsigned int uint ;
typedef unsigned char uchar ;
template<class T>inline void checkmax(T &a , T b){ if(a<b) a = b; }
template<class T>inline void checkmin(T &a , T b){ if(a>b) a = b; }
const int inf = 1 << 30 ;
const double eps = 1e-7 ;
const LL oo = 100000000LL * 100000000LL ; //1e16
const LL Mod = 1000000007 ; //1e9 + 7
const int NN = 110000 + 10 ;
char ch[ NN ] , str[ NN << 1 ] ;
int len ;
int P[NN<<1] ;
/*
str : 原字符数组,在每两个相邻的字符之间加入了一个‘#’(第一个之前
和最后一个之后也要加一个'#'),同时为了避免(1)处产生数组越
界,在最开始加入一个'$',在最后加入一个0 ;
P : 辅助数组,P[i]表示以i为中心,向右最多可以“走出”多少个字符,
( P[i] - 1 ) * 2 + 1 就是以i为中心的回文串的长度;
a : a = max{ a+P[a] > j + P[j] | j < i } ;
mx : mx = a + P[a] ; 以a为中心的回文串为:str[ a-P[a]+1 ....... a+P[a]-1 ]
*/
void solve(){
int mx , a , i , j , ans = 2 ;
P[0] = 1 ; a = 0 ; mx = 1 ;
rep(i , 1 , len){
if(i < mx){
P[i] = MIN( P[2*a-i] , P[a]+a-i ) ;
}
else{
P[i] = 1 ;
}
for( ; str[i+P[i]]==str[i-P[i]] ; ){ //(1)
P[i]++ ;
}
if( i + P[i] > mx ){
mx =i + P[i];
a = i ;
}
}
rep(i , 0 , len) checkmax( ans , P[i] ) ;
printf("%d\n",ans-1);
}
int main(){
int i , j ;
while( scanf("%s",ch) == 1 ){
len = strlen( ch ) ;
str[0] = '$' ; str[1] = '#' ;
rep(i , 0 , len){
str[i*2 + 2] = ch[i] ;
str[i*2 + 3] = '#' ;
}
len = len << 1 ; len += 2 ; str[len] = 0 ;
solve() ;
}
return 0 ;
}
Ural_1297:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#include <list>
#include <ctime>
#include <sstream>
#define rep(i,initial,end) for(i=(initial);i<(end);i++)
#define MAX(x,y) ((x)<(y)?(y):(x))
#define MIN(x,y) ((x)<(y)?(x):(y))
#define SZ(a) (sizeof(a))
#define MEM(a) ( memset((a) , 0 , sizeof(a)) )
#define MEME(a) ( memset((a) , -1 , sizeof(a)) )
#define MEMX(a) ( memset((a) , 0x3f , sizeof(a)) )
using namespace std;
typedef long long LL ;
typedef unsigned long long ULL ;
typedef unsigned int uint ;
typedef unsigned char uchar ;
template<class T>inline void checkmax(T &a , T b){ if(a<b) a = b; }
template<class T>inline void checkmin(T &a , T b){ if(a>b) a = b; }
const int inf = 1 << 30 ;
const double eps = 1e-7 ;
const LL oo = 100000000LL * 100000000LL ; //1e16
const LL Mod = 1000000007 ; //1e9 + 7
const int NN = 110000 + 10 ;
char ch[ NN ] , str[ NN << 1 ] ;
int len ;
int P[NN<<1] ;
/*
str : 原字符数组,在每两个相邻的字符之间加入了一个‘#’(第一个之前
和最后一个之后也要加一个'#'),同时为了避免(1)处产生数组越
界,在最开始加入一个'$',在最后加入一个0 ;
P : 辅助数组,P[i]表示以i为中心,向右最多可以“走出”多少个字符,
( P[i] - 1 ) * 2 + 1 就是以i为中心的回文串的长度;
a : a = max{ a+P[a] > j + P[j] | j < i } ;
mx : mx = a + P[a] ; 以a为中心的回文串为:str[ a-P[a]+1 ....... a+P[a]-1 ]
*/
void solve(){
int mx , a , i , j , ans = 2 ;
P[0] = 1 ; a = 0 ; mx = 1 ;
rep(i , 1 , len){
if(i < mx){
P[i] = MIN( P[2*a-i] , P[a]+a-i ) ;
}
else{
P[i] = 1 ;
}
for( ; str[i+P[i]]==str[i-P[i]] ; ){ //(1)
P[i]++ ;
}
if( i + P[i] > mx ){
mx =i + P[i];
a = i ;
}
}
rep(i , 0 , len) checkmax( ans , P[i] ) ;
rep(i , 0 , len){
if( ans == P[i] ){
rep(j , i-P[i]+1 , i+P[i] )
if( str[j]!='$' && str[j]!='#') printf("%c",str[j]);
printf("\n");
return ;
}
}
}
int main(){
int i , j ;
while( scanf("%s",ch) == 1 ){
len = strlen( ch ) ;
str[0] = '$' ; str[1] = '#' ;
rep(i , 0 , len){
str[i*2 + 2] = ch[i] ;
str[i*2 + 3] = '#' ;
}
len = len << 1 ; len += 2 ; str[len] = 0 ;
solve() ;
}
return 0 ;
}