Manacher算法

马拉车算法解决最长回文字串的问题

时间复杂度:O(n)

传统思想:以一个字符为中心,向两边扩大,就能返回最长回文字串,但是长度为偶数的字符串是不成立的,需要分情况讨论,而且算法时间复杂度 o(n^2) ,也可以使用动态规划,时间复杂度仍为o(n^2)

解决办法:在传统方法的基础上将每个字符两边添加字符 # ,然后再向两边扩展,这样奇数和偶数的回文串都找到了!

问题:添加的字符是不是要求字符串中没出现的字符?

  • 不是,随便添加,因为无论什么时候都是实际上有的的和有的比较,新添加的和新添加的比较

Manacher算法实现

讲解:

  1. 首先沿用了暴力解法的中心扩展思想,从第一个字符向后遍历,为了解决偶数字符串问题,在每个字符周围插入字符 ‘#’,例如字符串“ababa”变为“#a#b#a#b#a#”,新字符串长度变为``2 * str.length() + 1`

  2. 算法的优点在于对向后遍历过程中优化了回文串判断的逻辑,不同于暴力算法,每个字符都从该字符开始从中心扩散,而Manacher算法类似于KMP将之前比较过的结果利用起来了,避免了反复的重复判断

  3. 算法核心讲解:

    1. 定义变量:R:最右回文右边界,C:中心点位置,arr[str.length]:用来保存每个位置为中心的回文半径(从中心点开始向边缘计数)长度
    2. R的意思是在整个字符串的遍历过程中保存每次i位置为中心的回文串的最右侧位置构成一个回文区间,在区间内的字符可以通过回文区间的特性,缩减判断步骤,甚至直接不用判断
    3. C的意思是,R为右边界的回文串的中心位置,左边则对应L
    4. 每次判断i位置的字符的回文串的时候都保留一下到达的最右侧位置,把最右侧位置给R,这样就能不停的扩展这个回文串,更新会文串时要同时更新中心点C
    5. 大概的图解
    6. 一共有四种情况,分为两大种
    7. (1)、当前遍历的i位置的字符不在回文区间中,那么这种情况就不会右优化的空间,之间按照暴力方法向后遍历
    8. (2)、当前遍历的i位置的字符在回文区间中(三种情况)
      1. 以i为中心的回文串(L…iil…ii…iir…c…il…i…ir…R)整个都在R以内,根据回文特性,i位置的回文串的长度和ii位置是完全相同的。所以arr[i] == arr[ii],i和ii是关于对称的,所以ii = 2 * c - i,所以arr[i] = arr[2 * c - i],这种情况完全不需要判断
      2. 以i为中心的回文串一部分在LR这个区间之外(iil…L…ii…iir…c…il…i…R…ir)那么就认为i到R这之间是不需要判断的即R - i这个长度是一定是回文的,但是R之后是否是回文还是需要判断的,同时伴随着判断结束的R的更新,一旦R右侧仍有字符构成回文,那么,R和C将同时更新
      3. 以i为中心的回文串压了LR的线。这种情况就是arr[i] = arr[ii] = R - i
    9. 至此4种情况梳理结束,循环结束后arr数组中最大值 - 1 就是最长回文子串长度(因为字符串是被我加过#字符扩展的,新字符串长度为2 * len + 1,而arr[i]是最大回文半径长度,减一以后刚好是原串中最大回文字串的长度例如“#a#b#a#”,arr[i]最大为4,串长为7,实际上串长为3,最大回文字串长度为3)
  4. 代码实现

    package Manacher;/*** @author 孙东宇* 创建时间:2022/04/17* 介绍:Manacher算法,解决回文串问题*/
    public class Manacher {public static void main(String[] args) {String s = "babab";manacher(s);}public static int manacher(String s) {if (s == null || s.length() == 0) {return 0;}// 将 字符串添加‘#’字符char[] str = manacherString(s);// 定义回文"半径"数组int[] arr = new int[str.length];// 回文串中心int c = -1;// 回文右边界再往右一个位置(为了方便实现代码)int r = -1;// 扩展字符串的最大回文字串长度int max = Integer.MIN_VALUE;// 对每个位置求回文半径,原理和暴力方法相同都是以i为中心// 向两边扩展for (int i = 0; i < arr.length; i++) {// 先确定每个位置最小确定的不用判断的区域,先给arr[i]赋值,减少判断量// 解读:// 1. r > i  是判断i是否再r之内,如果不在就是第一种情况// 2.第二种情况右3种小情况,// 2.1,i所在的区域都在r之内,那么就是arr[2 * r - c]对称过去的i// 2.2,如果有的部分不在,那么就是 r - i 为回文半径长度(但是需要判断是否需要扩大)// 2.3,如果压线,那么arr[2 * r - C] 和 r - i 是相等的// 所有情况都是围绕arr[2 * i - c] 和 r - i 所以总结起来就是在两个之间取最小值arr[i] = r > i ? Math.max(r - i, arr[2 * i - c]) : 1;// 将 r 向两边扩展// 虽然只有 2.3 这一种情况需要将r向两边扩展更新,但是为了缩减代码长度,将所有都进行判断扩展// 不能扩展到数组越界while (i + arr[i] < str.length && i - arr[i] > -1) {if (str[i - arr[i]] == str[i + arr[i]]) {arr[i]++;} else {break;}}//更新右边界Rif (i + arr[i] > r) {// r的定义、最右侧再往右一个位置r = 1 + arr[i];// 更新中心点c = i;}max = Math.max(max, arr[i]);}return max - 1;}// 插入字符‘#’private static char[] manacherString(String s) {char[] charArr = s.toCharArray();char[] res = new char[charArr.length * 2 + 1];int index = 0;for (int i = 0; i < res.length; i++) {res[i] = (i & 1) == 0 ? '#' : charArr[index++];}return res;}
    }
    

Manacher算法详解相关推荐

  1. 【最长回文子串】Manacher算法详解

    写在前面 manacher算法解决最长回文子串以及变形问题的时间复杂度为O(n). 如果你想囫囵吞枣,只需要使用到该算法,你可以直接把代码拿走:但如果你想深入了解这个算法的工作原理和关键部分解读,还是 ...

  2. manacher算法详解(马拉车算法)

    马拉车算法 Manacher算法是由题目"求字符串中最长回文子串的长度"而来.比如 abcdcb 的最长回文子串为 bcdcb ,其长度为5. 回文:正着念,反着念都一样 暴力解不 ...

  3. Manacher Algorithm马拉车算法详解

    Manacher Algorithm马拉车算法详解 链接:https://www.zhihu.com/question/37289584/answer/465656849 中心扩展算法 我们先来看一个 ...

  4. Matlab人脸检测算法详解

    这是一个Matlab人脸检测算法详解 前言 人脸检测结果 算法详解 源代码解析 所调用函数解析 bwlabel(BW,n) regionprops rectangle 总结 前言 目前主流的人脸检测与 ...

  5. 图论-最短路Dijkstra算法详解超详 有图解

    整体来看dij就是从起点开始扩散致整个图的过程,为什么说他稳定呢,是因为他每次迭代,都能得到至少一个结点的最短路.(不像SPFA,玄学复杂度) 但是他的缺点就是不能处理带负权值的边,和代码量稍稍复杂. ...

  6. C++中的STL算法详解

    1.STL算法详解 STL提供能在各种容器中通用的算法(大约有70种),如插入.删除.查找.排序等.算法就是函数模板,算法通过迭代器来操纵容器中的元素.许多算法操作的是容器上的一个区间(也可以是整个容 ...

  7. 粒子群(pso)算法详解matlab代码,粒子群(pso)算法详解matlab代码

    粒子群(pso)算法详解matlab代码 (1)---- 一.粒子群算法的历史 粒子群算法源于复杂适应系统(Complex Adaptive System,CAS).CAS理论于1994年正式提出,C ...

  8. 基础排序算法详解与优化

    文章图片存储在GitHub,网速不佳的朋友,请看<基础排序算法详解与优化> 或者 来我的技术小站 godbmw.com 1. 谈谈基础排序 常见的基础排序有选择排序.冒泡排序和插入排序.众 ...

  9. 目标检测 RCNN算法详解

    原文:http://blog.csdn.net/shenxiaolu1984/article/details/51066975 [目标检测]RCNN算法详解 Girshick, Ross, et al ...

最新文章

  1. 用了这么久 IDEA,你竟然不知道有个功能叫自动补全!
  2. angularjs html5模式,angularjs – 确定在控制器中启用了HTML5模式
  3. C#中一道关于多线程的基础练习题——模拟仓库存销过程
  4. 关于毕业租房的一些碎碎念。
  5. python背景怎么自定义铃声_Python 上课铃声的定时播放(具有较强的自我管理能力.jpg)...
  6. 控制台怎么查看错误的详细信息_js错误处理,quot;try..catchquot;
  7. linux硬盘分区为什么总有1M,3步实现制作并挂载自己的Linux硬盘分区
  8. mysql InnoDB 行锁分析
  9. 解决Charles Response 中文乱码
  10. Hello Qt——QtCreator代码格式化
  11. 关于SBUS信号在单片机中的一些个人理解
  12. 工业互联网:制造业的二次升级
  13. 电信 IPRAN 设备组网方案_IPRAN 5G典型组网
  14. 5G NR 下行同步SSB(1)-- SSB时频资源
  15. 日常运维工作的知识体系
  16. 华硕电脑一开机就等待按F1然后自动进入BIOS界面如何解决
  17. 》技术应用:大数据产品体系
  18. 期末小结(一). 专业技术
  19. C++坦克大战(新手)
  20. wav to image concat 版

热门文章

  1. 企业10大管理流程图,数字化转型从业者必备!
  2. 微信自带浏览器被输入法阻挡文本框的 jQuery 解决方法 by FungLeo
  3. 汽车方向盘助力转向器如何接线_方向盘突然变重?千万不要忽视,很可能是这几个地方出问题了!...
  4. Excel 高级筛选空白单元格无效解决方案
  5. python 开立方注意事项
  6. 《编译原理》复习第1章~第5章
  7. 启动城市级智慧停车系统,让每一次出行都更加顺畅
  8. 【unity】关于枪口瞄准的趣事
  9. Java8 日期时间的操作技巧
  10. 7-126 时间差 (10分)