Manacher 算法

Manachar算法:处理字符串中的回文串问题。

Manacher算法对原字符做了填充:

原字符串: daabaac    新字符串:   #d#a#a#b#a#a#c#

原回文子串: aabaa    新回文子串: #a#a#b#a#a#

  1. 字符串的回文性不会改变;
  2. 回文子串长度是奇数;
  3. 新回文子串的回文半径减1 是原回文子串的长度。

初始思路: 以回文串中心轴pos两侧等距的字符,为中心轴的回文串的情况是对称的。

     同时要保证左右两侧的回文串不能超过pos回文串的边界。

辅助变量:

Mp【】:存放当前字符的回文半径。

Mx: 已知回文串的右界中最大的。

  使当前字符尽可能在mx左侧, 利用pos计算出左侧对称中心轴的位置 pos-( i - pos ), 即2*pos - i;

pos:MaxRight对应的中心轴的位置。 

关键步骤:

  如果Mx在 当前字符位置 i 的左侧 , 当前字符回文情况不可知, Mp【 i 】= 1;

  如果Mx在当前字符位置 i 的右侧, 得知 对称pos 的左侧中心轴的回文半径 Mp【 2*pos - i 】; 左侧中心轴离pos回文左界的距离是 Mx - i ,

若 Mp【 2*pos - i 】 < Mx - i , 左侧的回文不会出左界, 更不会出右界。 利用性质, 当前字符的回文半径可初始化为Mp[ 2*pos - i ];

若 Mp【 2*pos - i 】 > Mx - i,  左侧回文出界, 无法保证, 但回文半径为 Mx - i 的子串 没有出界,  当前字符的回文半径可初始化为 Mx - i ;

  初始化完之后, 就可以向两侧扩展匹配了。

  之后要更新 Mx 和相应的 pos。

代码:

 for (int i = 0; i<l; i++)  {
    Mp[ i ] = mx > i ? min( Mp[ 2 * pos- i ],  mx - i ) : 1;
    while ( Ma[ i + Mp[ i ] ] == Ma[ i - Mp[ i ] ] )  Mp[ i ]++;
    if ( i + Mp[ i ] > mx )   {
       mx = i + Mp[ i ];
         pos = i;
    }
 }

 

posted on 2018-02-04 21:56  焚香谷  阅读(87)  评论(0编辑  收藏  举报