Manacher 算法
Manachar算法:处理字符串中的回文串问题。
Manacher算法对原字符做了填充:
原字符串: daabaac 新字符串: #d#a#a#b#a#a#c#
原回文子串: aabaa 新回文子串: #a#a#b#a#a#
- 字符串的回文性不会改变;
- 回文子串长度是奇数;
- 新回文子串的回文半径减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;
}
}