1.Manacher算法
一个串中,找到最长的回文子串。
1.1 暴力解决
得解决长度为奇数的回文和长度为偶数的回文。
1.1.1 奇回文
- i位置自己肯定构成回文;长度为1
- i+1位置和i-1位置相不相等?相等,构成回文。长度为3
- i+2位置和i-2位置相不相等?相等,构成回文。长度为5
1.1.2 偶回文
1.1.1 中的方法不适用
1.1.3 解决方法
向字符串的开头、中间和结尾加东西。
既有奇回文:11311
又有偶回文:11
处理:
然后计算每一位的回文长度:
最终结果是:11/2=5
此方法适用于奇回文和偶回文。
添加的字符无论啥都可以。因为添加的字符不会和原字符串中的字符进行比较,只是和添加的字符比较(实轴永远和实轴比较,虚轴和虚轴比较)。
时间复杂度:
2.概念
2.1 回文直径
回文半径
在Manacher算法中,需要准备一个数组——回文半径数组。存以每个位置为中心的情况下,可括出来的回文半径的长度。
加速:数组后面的位置的值能否利用前面的值,减少计算,实现加速。
2.2 最右回文右边界
所有回文半径中最靠右的位置。
初始:R在-1的位置;
0位置:只能扩到自己;
1位置:可以扩到2位置(#1#)
2位置:不行
3位置:可扩到6位置(#1#2#1#)
表示的是:每个位置下,R最右能到的位置。
3右边扩到了最右的0位置。
2.3 回文右边界的中心
C表示:第一次取得这个最右边界的中心位置。
0位置时,它的C是3.
3的右边界到它右边的1,后面的2的右边界也是2后面的1,但是1的C=3的位置(记录的是第一次到达的)。
3.分情况讨论
3.1 i位置不在回文右边界中——
比如刚开始的时候,R在-1位置,i在1位置。就是i不在回文右边界。
则暴力扩。
时间复杂度:R的变化范围是从0~N,所有扩的范围都在推后R,而且不会回退,所以总的时间复杂度是
3.2 i位置在回文右边界的里面
位置1的回文右边界在2位置,当i为2时,它在回文右边界的里面。
3.2.1 i'的回文半径在L里面——
由C和R得到回文左边界L,假设此时i的位置如图所示:
C肯定在i的左边。关于C做i的对称点i':
由回文数组中i'的回文半径,可得到一下多个可能性:
可能性1:i'的回文区域在L和C的中间
举例:
C:在F的位置
F的R和L在K位置
i'和i在b的位置
i'为重新的回文是aba,完全在L和C中间。
结论:i位置的回文半径和i'的相等
证明:
- 小R'到小L'之间肯定是回文结构
- 且这个范围不会扩的更大。
3.2.2 L和R没包住小L和小R——
举例:
此时i的回文半径就是i到R。
证明:
过程:
3.2.3 L压线
举例:
这种i的回文半径能不能扩的更大需要尝试。上例中,由于k=k,所以可以扩。
如下图,k≠s,不可以扩
时间复杂度同3.1:
4.应用
给定一个字符串,要求只能在串后面添加字符,使之成为一个回文串。要求添加的字符数最少。
比如,给定:
添加cba会使上串变为回文串,且最短。
它就是在求必须包含最后一个字符("1")的情况下,最长回文串是多少。前面不是的部分(“abc”)逆序过来,就是答案。
改写Manacher:
- 一直求每个位置的回文半径。
- 当R到达最后一个位置的时候,停。得到回文半径到R的位置C。此时有R和C。
- 然后将R以C为中心,对称到R’。即得包含最后一个位置的最长回文串。
- 然后将前面剩余部分逆序,添加到给定字符串的后面。
比如: