Template of MANACHER for Solving Palindromes Substring

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..i1 , 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{mxli,r2posi} . Position 2posi is the symmetric position of position i , mxli is the distance between the position i and the furthest position. But if not, we can only know that ri0 . After we got the minimum value, try to push ri forward as far as you can. After solve ri , change variable pos and mxl into new values if needed.

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.

發佈了71 篇原創文章 · 獲贊 160 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章