博客已经搬家,请前往http://gqqnbig.me/ 阅读格式良好的文章。

本文将一步一步构造Manacher算法,心急的一定看不懂!请先练习下面的习题。

探索最长回文串性质

题1:已知字符串以center为中心对称,求完整的字符串。

abcd???|
center

abcdcba|
center

题2:接上题,abcdcba后面还有一些字符,以center2为中心,最大对称半径[ref]半径大于等于1。[/ref]为7,求完整的字符串。

答根据center2的对称性质,可以知道字符串为

abcdcba???abcdcb??

又根据center2最大对称半径为7,而不是8,所以c后面一定不是b(标识为b)。center3的对称半径确定!而且,center关于center2的对称点center3的索引号为center2*2-center=8*2-3=13。对称半径为center2+7-center3=8+7-13=2。

题3:稍微调整上题,若center2在a,对称半径为8,求完整的字符串和center3的对称半径。

答:字符串为

babcdcbabcdcbab?

center3=center2*2-center=7*2-4=10。对称半径为center2+8-center3=7+8-10=5。这样对吗?

看起来半径不正确!应该同center一样都是4。问题出在哪里呢?明明用的是跟题2一样的公式啊!因为题2跟题3情况不同。题2 center左边超出了center2的对称范围;而题3 center左边没超出center2的对称范围。center3的半径确定。题4:同样,center在x,半径为2,center2在a,半径为5。求完整的字符串和center3半径。

答:根据center2的对称性补全center2范围内的字符。又因为center2的对称半径为5而不是6,索引11位的字符不是c。

cc dxdbab7dxd c11 ?12????

所以center3的半径就是2了吗?不一定哦!因为我们只知道索引11位的字符不是c,但它可能是b,这样就与索引7位的b匹配,对称半径达到3。同样地,我们也不知道索引12位的字符是什么。所以,在center和center2的左边界重合时,我们只知道center3半径的最小值。 根据这三道例题,我们已经总结出回文字符的半径性质:

  1. 当center1范围左超center2范围(简称左超),center3的半径可由计算得出,为确切值。
  2. 当center1范围内含于center2范围(简称内含),center3的半径等于其关于center2的对称点半径,为确切值。
  3. 当center1左边界与center2左边界重合(简称接边),center2半径大于等于其关于center2的对称点半径,值不确定。

在情况1、2中,求的是确切值,所以即使center3内含于多个对称范围,每个对称范围求出的半径都一定是一样的。在情况3中,所有对称范围的计算值的最大值是center3半径的最小值。

基本代码

下面给出基本代码。[code lang="java"]public static int getPalindromeLength(String s){if (s.length() == 0)return 0;StringBuilder sb = new StringBuilder(s.length() * 2 + 1);sb.setLength(sb.capacity());for (int i = 0; i < s.length(); i++)sb.setCharAt(i * 2 + 1, s.charAt(i));s = sb.toString();int[] radii = new int[s.length()];for (int center = 0; center < s.length() - 1; center++) // O(n){boolean notSure = true;// 检查center是否在某个对称区域的右半边for (int center2 = center - 1; center2 >= center / 2; center2--){if (center2 + radii[center2] > center) // center在以center2为中心的对称区域的右半边{int c1 = center2 * 2 - center;assert c1 >= 0;if (c1 - radii[c1] < center2 - radii[center2])// 左超,半径确定{radii[center] = center2 + radii[center2] - center;notSure = false;break;}else if (c1 - radii[c1] > center2 - radii[center2]) // 内含,半径确定{radii[center] = radii[c1];notSure = false;break;}else// 接边,半径可能变化radii[center] = Math.max(radii[c1], radii[center]);}}if (notSure){// ccxbabxbabxcc// 0123456789012/* * 索引6的x关于索引4的a对称,根据索引2的x得对称半径1。 但实际上索引6的x是整个字符串的对称中心。 */int r = radii[center];while (center - r >= 0 && center + r < s.length() && s.charAt(center - r) == readChar(s, center + r))r++;radii[center] = r;}}int maxRadius = radii[0];for (int i = 0; i < radii.length; i++)maxRadius = Math.max(maxRadius, radii[i]);return (maxRadius - 1);}private static char readChar(String s, int index)//这个方法可用来查看计算复杂度{System.out.println("读取字符" + index);return s.charAt(index);}[/code]

现在分析复杂度,令比较运算为耗时间的操作。该代码通过notSure变量,仅当i关于center2的对称点接边的时候才读取字符来比较。前面性质分析中说的是左侧接边,根据对称性也是右侧接边。进入if (notSure)分支后继续读取更右边的字符,然后记录在radii里。以后,从radii里读就可以了。建议亲手运行代码看看,会发现程序不会重读前面读过的字符,不会读了012345,然后又读2345。既然程序只读取字符2n次,那么比较进行了n次,所以时间复杂度是O(n)。网上很多代码与上面的代码不太一样,有id、mx什么的,尤其有一个变量记录什么最右边的位置,不太好懂。读者如果理解了上面的基本代码,那么可以再看下下面的变形代码,变形代码与网上的代码比较像。变形代码的复杂度同样是O(n)。[code lang="java" title= language=]public static int getPalindromeLength2(String s){if (s.length() == 0)return 0;StringBuilder sb = new StringBuilder(s.length() * 2 + 1);sb.setLength(sb.capacity());for (int i = 0; i < s.length(); i++)sb.setCharAt(i * 2 + 1, s.charAt(i));s = sb.toString();int[] radii = new int[s.length()];int rCenter2 = 0;// 右边界最大的cfor (int i = 0; i < s.length() - 1; i++) // O(n){// 检查center是否在某个对称区域的右半边if (rCenter2 + radii[rCenter2] > i) // i在以center2为中心的对称区域的右半边{int c1 = rCenter2 * 2 - i;assert c1 >= 0;if (c1 - radii[c1] < rCenter2 - radii[rCenter2])// 左超,半径确定radii[i] = rCenter2 + radii[rCenter2] - i;else// 不左超。但如果接边,半径可能变化radii[i] = radii[c1];}// 如果右最大的c都不包括i,那么其他c更不会包括了。if (i + radii[i] == rCenter2 + radii[rCenter2])// 接边{int r = radii[i];while (i - r >= 0 && i + r < s.length() && s.charAt(i - r) == readChar(s, i + r))r++;radii[i] = r;// 接边后超右边比较,半径可能更大!if (i + radii[i] > rCenter2 + radii[rCenter2])rCenter2 = i;}}int maxRadius = radii[0];for (int i = 0; i < radii.length; i++)maxRadius = Math.max(maxRadius, radii[i]);return (maxRadius - 1);}[/code]

参考资料

[CiteWeb author="xiangzhai" url="https://github.com/xiangzhai/leetcode/blob/master/question/longest-palindromic-substring-part-ii.md" title="最长回文子字符串 第二部" publisher="" date="2014-02-14" accessdate="2015-02-06"]

MANACHER最长回文算法相关推荐

  1. Manacher 最长回文子串

    用途 求最长回文串, 过程中更新max(Maxlen,RL[i]−1)max(Maxlen,RL[i]-1)max(Maxlen,RL[i]−1) 求回文串的数量,∑i=0lenRL[i]2\sum_ ...

  2. manacher最长回文子串

    https://www.luogu.org/blog/codesonic/manacheralgorithm 先放上洛谷的链接,毕竟讲的真好 两道例题 luogu4555 SP7586 inline ...

  3. manacher算法----O(n)最长回文串

    manacher算法----O(n)最长回文串 分类:字符串 (126)  (0)  举报  收藏 manacher的时间复杂度为O(n),后缀数组好像可以处理O(nlogn),但是有些变态题目可能卡 ...

  4. Manacher算法 , 实例 详解 . NYOJ 最长回文

    51 Nod http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1089 Manacher 算法 定义数组 p[i]表示以i为 ...

  5. Manacher 求最长回文子串算法

    Manacher算法,是由一个叫Manacher的人在1975年发明的,可以在$O(n)$的时间复杂度里求出一个字符串中的最长回文子串. 例如这两个回文串"level"." ...

  6. Manacher's algorithms(马拉车算法)最长回文子串

    最长回文子串 https://leetcode-cn.com/problems/longest-palindromic-substring/ 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 ...

  7. 通俗易懂的最长回文串图解、说明及Java代码(中心扩散法和Manacher算法)

    1. 回文串 作为程序员,回文串这个词已经见怪不怪了,就是一个字符串正着读和反着读是一样的,形式如abcdcba.bbaabb.这里涉及到奇回文和偶回文,奇回文指回文串的字符数是奇数,偶回文指回文串的 ...

  8. hdu 3068 最长回文(manacher算法)

    最长回文                                                                         Time Limit: 4000/2000 M ...

  9. HihoCode1032 最长回文子串 manacher算法

    求最长回文子串的算法比较经典的是manacher算法 转载自这里 首先,说明一下用到的数组和其他参数的含义: (1)p[i] : 以字符串中下标为的字符为中心的回文子串半径长度: 例如:abaa字符串 ...

最新文章

  1. 倍增LCA NOIP2013 货车运输
  2. 《背包问题》 动态规划
  3. Storyboard初体验
  4. 51单片机的配p10端口c语言,stc12c5a16s2的单片机的p5口做普通端口怎么定义?
  5. 排查指南 | 两个案例学会从埋点排查 iOS 离线包
  6. BugFree2.1.3升级到BugFree3.0.2
  7. 合并排序算法排序过程_合并排序| 用于大型输入的最佳排序算法之一
  8. 优秀程序员必备素质——快速调试
  9. ubuntu静态IP设置
  10. 敏捷开发智慧敏捷系列之六:之一~之五的小结
  11. android自定义悬浮控件
  12. 笔记本显示网络电缆被拔出怎么解决_电脑显示“网络电缆被拔出”怎么办?
  13. 动易CMS - 模板的一些常用标签
  14. js获取浏览器信息及版本(兼容IE)
  15. Echarts 柱状图配置圆角
  16. 19年6月六级翻译词汇
  17. perf Examples
  18. 使用lux(annie)下载视频
  19. c语言pl是什么意思,【问答】求助!PL-L PL-S PL-C PL-后面的字母什么意思? - 邦阅网-发现真实的外贸服务商...
  20. ESP8266开发之旅 阿里云物联网平台篇⑤ LED智能灯控制系统(使用HTTPS认证再连接)

热门文章

  1. Autohotkey全选复制并保存剪切板文本至以时间命名的文本文件
  2. 浅谈Java三层架构
  3. Oracle数据库的配置文件丢失或损失,重新执行pfile启动
  4. dxf geojson 转换_wkt转换geojson
  5. 一个画质很好的俄罗斯方块代码(c++)
  6. html如何做成弹窗,js+html+css制作弹窗
  7. 好用的mac软件下载网站
  8. 国内外火控计算机发展水平,火控计算机软件执行地址跟踪系统的研究
  9. vant 自义定 tabBar 图标和颜色
  10. 丁一凡:中国经济的三大优势--20190511