The algorithm of Manacher is a method for searching all the substrings which are in the form of palindrome in O(n) time.
//programed under gcc environment
#include<stdio.h>
#include<string.h>
int min(int _x,int _y){
//to choose a smaller integer
return _x < _y ? _x : _y;
}
//data definations
//maxl: the longest length for str
#define maxl (1000000+1)
//r:radius in the processed string
// -> the offset from middle to the end in a palindrome
int r[maxl*2];
//r is also the real length in the formar string
//str:the string for input
//chr:str with separator
char str[maxl],chr[maxl*2];
void manacher(){
//translate str into '#'
int len=strlen(str),i;
//i<=len means including the end flag '\0'
for(i=0;i<=len;i++){
chr[ 2*i ]='#';
chr[ 2*i+1 ]=str[i];
}
//mxl: right set of availeble segment
//pos: the middle for the furthest palindrome
int pos=0,mxl=0;
r[0]=0;
//for each offset in chr,solve once
for(i=0;i< 2*len+1 ;i++){
if(mxl>i){//check if in available segment
r[i]=min(mxl-i,r[2*pos-i]);
}else r[i]=0;//not in
while(//check if "r" can be larger
i+r[i]+1 < 2*len+1 && i-r[i]-1>=0 &&
chr[i+r[i]+1] == chr[i-r[i]-1]
//!attention: "i+r[i]+1 < 2*len+1" not "<len"
)r[i]++;//push forward once
if(i+r[i]>mxl){//check and change available area
mxl=i+r[i];//new right set
pos=i;//new middle for palindrome
}
}
}
void outp(){
int i;
for(i=0;chr[i];i++){
//output message "chr" and "r"
printf("%c:%5d\n",chr[i],r[i]);
}
}
int main(){
//for test only
while(1){
//input string
scanf("%s",str);
//run the algorithm "manacher"
manacher();
//output message of MANACHER
outp();
}
return 0;
}
There are two main ideas in this algorithm:
Set Separator
For the symmetric center of a palindrome can be set in the middle of two characters (but not on a letter), such as “abba” ‘s sym-cen is between the two “b”s, we have to make two different algorithm if we want to solve both kinds of palindromes. Why not put something between each pair of adjacent chars, such as pocessing “abba” into “#a#b#b#a#”. This allow us to use only one algorithm to solve the whole problem.
Keep Track of the Furthest Reached Place.
For each position in the pocessed string, we use ri to record the radius of a position, that is the offset of the right set of the longest string, whose middle position is located in chri , from the middle of this substring. (Obviously, the so-called radium in the processed string is also the length of the palindrome in the unprocessed string.)
When we have got the values of
r1..i−1
, how can we get the value of
ri
. We can record two value called “pos” and “mxl”. mxl is the furthest position you have been to, pos is the middle position of the substring (of cause, palindromic) by which you arrived mxl. If i lies between pos and mxl,
ri
can’t be less than
min{mxl−i,r2∗pos−i}
. Position
2∗pos−i
is the symmetric position of position
i
,
mxl can only become larger, and we make full use of the message we’ve got, this algorithm can be done in O(n) time .
Finally
Please forgive me for my grammatical and spelling mistakes.