复杂算法介绍[3]-Manacher算法
Manacher算法,江湖人称马拉车算法,用来解决最长会问串问题,举个例子:
假设字符串是
fabccba
最长回文串就是abccba
如何快速求出这个最长的回文串
1、暴力尝试
寻找以每个字符为中心的最长回文子串,但是回文子串有奇数和偶数的区分,例如回文串abccba的中轴线是在两个c中间,并不是独立的字符,为了统一奇数偶数的情况,需要对字符串进行补长变成:#f#a#b#c#c#b#a#,也就是每个字符串前面都补了一个#,字符串最后也补一个#,补出的#就是之前看不见的中轴线,现在计算以每个字符为中心的最长回文串,就能覆盖回文串长度为偶数情况,如果回文串长度为基数,由于原有字符两侧补的都是#,每个字符两侧补上#后不影响回文性质,且最长回文串就是新串最长回文串的一半,由于需要遍历以每个字符为中心的字符串,所以时间复杂度为:O(N²)
Manacher算法就是用来优化这个流程,让时间复杂度能达到O(N)
2、 Manacher算法
先明确几个基本概念【假设原字符串str1补上#后变成str】:
- 1)、构造pAr数组,数组中的第i个元素表示以字符串str第i个字符为中心的最长回文半径【回文半径就是以i为中心,到回文左边界或者右边界的距离,a的回文半径是1,a#a中#的回文半径是2】
- 2)、回文右边界R【不一定是最长的】
- 3)、回文右边界对应的中心点C
初始R=-1,C=-1代表无效位置
对于任意时刻的扫描位置I(字符串的第i个字符),会有两种情况
- 1)、I>R,即i的位置大于回文最右边界,此时只能和暴力尝试一样,扫描仪I为中心的最长回文串,并更新对应变量值
- 2)、I<=R,我们重点讨论这种情况
I<=R时,假设现在字符串被切割成如下结构:
假设回文左侧边界是L,右侧是R,由于I在回文右侧内部,所以I字符关于c肯定有一个对称字符I’,如下图:
以位置I’为中心的最长回文子串回文半径存储在pAr数组中,可以直接拿到pAr[I’],会有以下几种情况:
- 1)、假设以I’为中心的最长回文串不会超过此时回文左侧的左边界,那么对应的以I为中心的回文串就不会超过回文右侧的右边界,也不可能成文最长的回文子串
图如下,草绿色的就是以I’为中心的最长回文串
由于两边对称,所以I两侧也是一样,如下图,最长回文串长度就直接可以取I’的值
- 2)、当以I’为中心的最长回文串超过此时回文左侧的左边界,如以下情况
由于以C为中心的回文串两边对称,我们一眼就能保证I左右两侧的回文大小如下
有没可能I的最长回文串,超过右边界?,出现下图粉色的匹配区域:
答案是不可能,证明如下:
因为
A = B逆序
A = E逆序 ===》B=E
假设存在图中粉色区域
那么
E=F逆序=B
所以以C为中心的最长回文串的右边界应该在F字符串的结束,和原始假设不符,所以当I’的回文半径超过L时,I最长回文子串边界只能是R
- 3)、当以I’为中心的最长回文串刚好等于此时回文左侧的左边界,那么一I为中心的回文串是否有可能超过右边界?答案是可能,还是以上面有粉红色区域的图为例,因为:A = E逆序,如果存在F使得E逆序=F,可以得出A=F,并不会扩展C为中心的最长回文串边界,不会违反大前提,所以就需要确定以I为中心的最长回文串,但是草绿色区域已经明确是回文,所以下一次匹配德位置从R+1位置开始即可
最终返回的就是pAry最大值-1,可以自己搞个字符串对应下