最大回文子串
马拉车算法(Manacher)
:::success
解决的问题:
以O(n)时间求出一个字符串的最长回文子串长度
:::
算法流程
如果求最大回文子串,暴力做法是从一个点开始,每次向左和右同时延伸一个单位,比较是否相同,但是这种方式比较难受的是如果字符串长度是偶数,那么可能对称中心不在字符上,而在两个字符之间,如果还想使用上面的方法就必须让指针在字符之间停留一下,所以考虑在每一个字符之间以及开头结尾(开头结尾添加是要让添加字符后的答案和未添加时的答案有一个对应关系)都添加相同的未出现的字符,这里用”#”表示,这样一来aba就变成了#a#b#a#,这样一来无论原串的长度为奇或偶转化后的字符串长度永远是奇数(2*l+1),这时会发现添加后的字符串找出来的最长回文子串长度永远等于原串的最长回文子串长度+1(无论原串长度为奇数或偶数),所以对改变后的字符串求解的答案-1就是答案。
引入Len数组表示一个字符向左或向右可延伸的最长回文长度,比如aba,那么Len[1]=2(ab)
当求Len[i]时Len[i_mirror]是已知的,又因为黑色区域都是回文的,所以Len[i]=min(Len[i_mirror],mx-i),之所以要和mx-i取一个较小的是因为可能左边的Len比较大,而对于当前位置的i+Len[i]超过了mx就会造成答案错误,因为mx右面的都还没有匹配过
代码
1 | string process(string s){ |
延伸求最大回文子串长什么样
既然有了最大回文子串的长度,也可以计算出匹配到最大长度时的对称中心下标,那么只要找到原串和处理过的字符串的下标对应关系就可以求出max回文子串长啥样了,经过模拟发现j=2(i+1)(j:处理过的下标),i-Len[i]+2是匹配到的最长回文子串的开头字符的下标,所以可以求得最大回文子串
1 | //修改此处即可 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Doraemon's Blog!
评论