【通俗易懂搞算法】一篇文章弄懂Manacher算法

Manacher算法

    • manacher算法解决的问题
    • 回文 最长回文子串
    • 最长回文子串解法
      • 解法1.0
      • 解法2.0
      • Manacher算法
        • 回文半径、回文直径
        • 回文半径数组
        • 之前扩的所有位置中所到达的最右回文右边界(R)
        • 取得更远边界的中心点的位置(C)
        • Manacher算法优化情形
          • Manacher算法优化情形总结
        • manacher算法代码实现

manacher算法解决的问题

  1. 求解最长回文子串的长度
  2. 大部分回文问题都可以用manacher算法
  3. 将求解的时间复杂度降到O(N)

回文 最长回文子串

注:此处是根据我的理解进行讲解,需要准确的定义,自行进行搜索,我的讲解只是为了让你们更好的理解

  • 回文

​ 字符串正着读反着读都是它本身,或者可以看作它是关于某一个轴对称。

​ 比如"123321" “aba” 就是回文。

  • 最长回文子串

    1. 一个字符串的子串(包括字符串本身),子串要求连续
    2. 是回文
    3. 最长

例:str为"abc112320de1"
根据最长回文子串的定义可以看出,"11"和"232"为回文子串,而“232”最长,所以“232”为最长回文子串,而"12321"不是,因为他是不连续的,也就不是str的子串。

最长回文子串解法

解法1.0

根据回文的定义我们可以想到通用的解法,就是能不能对字符串先进行遍历,然后看当前字符的左右字符是否相等,如果不相等,就直接返回当前回文长度,最开始的回文长度为1,如果相等回文子串长度加1,然后继续向左右两边扩充,不断反复,直到左右字符不等,或者到达字符串左右边界。根据这个想法,我们对上面的str字符串进行该操作。
在这里插入图片描述

通过该操作,我们似乎可以得到最长回文子串,但是,这种做法,存在一个问题,就是他忽略了回文长度为偶数的回文!!显然,假如回文是偶数的话,我们不能采取这种做法。那我们就需要对上面的想法进行改进,也就是解法2.0.

解法2.0

在原来的字符串的每个字符左右两边填充特殊字符,然后按照解法1.0的步骤求出每个字符的回文长度,然后取出最大的回文字符长度除以2,得到最终的最长回文子串长度,还是以上面的str字符为例,进行讲解。

在这里插入图片描述

我们可以看出,这样的做法对于偶数回文“11”,奇数回文“232”都求出来了,这里的除以2是向下取整不然结果长度会多1个。

理解了这种做法,我们来深入研究一下一些问题。

这里插入的特殊字符有限制吗?

答案是没有,这里的特殊字符没有什么限制,没有说非要是字符串中不存在的字符。这里你们可以看一下你们加了特殊字符,在求原来字符串的各个字符的回文长度的时候,这些特殊字符对于回文有没有影响?答案显而易见,是没有的,所以这里的特殊字符是没有限制的。

​ 这种结果的时间复杂度是多少?

​ 答案是O(N^ 2),为什么呢?这里不太好解释,我只能讲解个大概,求某一个位置的回文长度,他的往两边扩充要么扩充到左边界停,要么扩充到右边界停,字符串从左边界到字符串中间,字符串中间到字符串右边,扩充次数是个等差数列,所以时间复杂度是O( N^2 ), 假如有大佬能够讲解清楚,可以在评论区留言。

在这里插入图片描述

这里我们就引出了Manacher算法,因为它能将时间复杂度缩小到O(N)!!!假如你学过kmp算法,那么对于Manacher算法,你会觉得学起来很轻松,因为它借鉴了kmp算法的next数组进行加速,最终达到O(N)的时间复杂度。

Manacher算法

Manacher算法有四个概念需要理解分别是回文半径、回文直径,回文半径数组,之前扩的所有位置中所到达的最右回文右边界®和取得更远边界的中心点的位置©,这些概念先大致了解,等后面在详细讲解。

回文半径、回文直径

当你求解一个字符的回文字符串长度时,这个回文字符串的长度就是就是回文直径,而对这个回文字符串长度除2向上取整就是回文半径,以上面的str的回文子串“121”为例子,“121”的回文直径是3,回文半径就是2,也就是字符串的“21”或者“12”的长度。

回文半径数组

对于要求字符串的每个字符左右两边填充特殊字符,然后从左往右求每个字符的回文半径放入一个数组中,类似于kmp算法的next数组。

之前扩的所有位置中所到达的最右回文右边界®

这里我用一个例子进行讲解,文字难以表达,你从左往右看我推的过程就能看明白,假如不懂,可以在评论区留言。该值是int类型,在图中我用变量n表示。

在这里插入图片描述

取得更远边界的中心点的位置©

int类型,初始值为-1,中心点位置是随着R的值变化的,R变化则C也变化,R不变C也不变,这两个概念有点抽象,因为我们都不知道这两个概念有什么用,先大致的看一下,等后面用到了,自然就明白了。

在这里插入图片描述

Manacher算法优化情形

​ 这里的话,不要想太复杂,Manacher算法的思路还是跟解法2.0一样,但是它是为了提速,那么它提速就会有要求,就类似kmp算法,next数组里的数是-1,自然没有提速的办法,只能暴力扩充,看它的回文长度是多少,进而更新其他参数,直到满足提速要求,进行提速。

(1)当来到某个点的时候,这个点没有在最右回文右边界里,暴力扩充,不存在优化。

在这里插入图片描述

以第一个字符“#”为例子,此时最右回文右边界是-1,而中心点位置为0,此时,当前点位置不在最右回文右边界里,故直接暴力扩充。

(2)当所处点在最右回文右边界里,则存在优化。

假如所处点在最右回文右边界里,则说明当前点在中心点到最右回文右边界的内部。当前点可能跟中心点重合。

在这里插入图片描述

后续简写字母说明:

i :当前所在位置

i‘ :i关于中心点C对称位置

R:最右回文右边界

L:R关于中心点C对称位置

C:中心点的位置

按照 i‘ 的 回文状况对(2)大情形进行划分。

(2-1) i’ 自己的回文区域在L-R之间

在这里插入图片描述

此时i的回文半径跟i’的回文半径相同。

这个地方很好理解,因为L-R首先是关于C对称的,i跟i‘ 是对称的,那么i的回文半径不就跟i’的一样啦。

(2-2) i’ 自己的回文区域有一部分在L-R区域之外

在这里插入图片描述

此时i的回文半径就是i到R。

这里看图就能看明白,我就不多赘述了,总而言之,还是因为对称。

(2-3) i’ 自己的回文区域与L压线

在这里插入图片描述

此时i的回文半径只能说至少的i‘的回文半径,具体多少,还要继续扩,以上图为例,i的”abcdcba“子串肯定是回文子串,但是需要看k和?是否相等,如果相等,回文半径+1,不相等则当前大小就是回文半径。

Manacher算法优化情形总结

(1)当来到某个点的时候,这个点没有在最右回文右边界里,暴力扩充,不存在优化。

(2)当所处点在最右回文右边界里,则存在优化。

(2-1) i’ 自己的回文区域在L-R之间,此时i的回文半径跟i’的回文半径相同。

(2-2) i’ 自己的回文区域有一部分在L-R区域之外,此时i的回文半径就是i到R。

(2-3) i’ 自己的回文区域与L压线,此时i的回文半径只能说至少的i‘的回文半径,具体多少,还要继续判断。

manacher算法代码实现
/**
 * 将字符串变为处理串 字符数组
 * @param str
 * @return char[]
 */
public static char[] manacherString(String str) {
    char[] charArr = str.toCharArray();
    char[] res = new char[str.length() * 2 + 1];
    int index = 0;
    for (int i = 0; i != res.length; i++) {
        res[i] = (i & 1) == 0 ? '#' : charArr[index++];
    }
    return res;
}

public static int maxLcpsLength(String s) {
    if(s == null || s.length() == 0) {
        return 0;
    }
    char[] str = manacherString(s);  // 1221 -->#1#2#2#1#
    int[] pArr = new int[str.length];   //回文半径数组
    int C = -1;     //中心点
    int R = -1;     //最右回文右边界,这里是回文右边界再往右的一个位置,最右有效区是R-1的位置
    int max = Integer.MIN_VALUE;    //扩出来的最大值
    for (int i = 0; i != str.length; i++) { //对每个位置求回文半径
        //对两个大情况进行分析,判断不用求的回文半径是多少,也就是加速的地方
        //Math.min(pArr[2 * C  - 1],R - i)
            //pArr[2 * C  - 1]  2 * C  - 1就是i‘ 这个参数就是i’的回文半径。
            //R - i  i到R之间的距离
            //回文半径大于 i到r之间的距离 对应 2-2 回文半径大于L-R 取i-r
            //回文半径小于 i到r之间的距离 对应 2-1 2-3  回文半径小于L-R以及回文半径在L上 取i的回文半径
        pArr[i] = R > i ? Math.min(pArr[2 * C  - 1],R - i) : 1;
        //从不要求的区域开始往外扩,看能不能扩,能就是(1) (2-3)两种情况,不能则是(2-1)(2-2)
        //这里只是让代码更加简洁,避免过多的if判断
        while (i + pArr[i] < str.length && i - pArr[i] > -1) {
            if (str[i + pArr[i]] == str[i - pArr[i]])
                pArr[i]++;
            else {
                break;
            }
        }
        if (i + pArr[i] > R) {
            R = i + pArr[i];
            C = i;
        }
        max = Math.max(max, pArr[i]);
    }
    //回文半径向上取整了,所以会多1
    return max - 1;
}
}
        }
        if (i + pArr[i] > R) {
            R = i + pArr[i];
            C = i;
        }
        max = Math.max(max, pArr[i]);
    }
    //回文半径向上取整了,所以会多1
    return max - 1;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/678873.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PySpark特征工程(I)--数据预处理

有这么一句话在业界广泛流传&#xff1a;数据和特征决定了机器学习的上限&#xff0c;而模型和算法只是逼近这个上限而已。由此可见&#xff0c;特征工程在机器学习中占有相当重要的地位。在实际应用当中&#xff0c;可以说特征工程是机器学习成功的关键。 特征工程是数据分析…

工业网关有效解决企业在数据采集、传输和整合方面的痛点问题-天拓四方

一、企业背景概述 随着信息技术的飞速发展&#xff0c;工业互联网已成为推动制造业转型升级的关键力量。在众多工业企业中&#xff0c;某公司凭借其深厚的技术积淀和广阔的市场布局&#xff0c;成为行业内的佼佼者。然而&#xff0c;在数字化转型的道路上&#xff0c;该公司也…

Java中getBytes()方法

我以为旅人将我 热情都燃尽 —— 24.6.4 String.getBytes(String decode)方法会根据指定的decode编码返回某字符串在该编码下的byte数组表示 而与getBytes相对的&#xff0c;可以通过new String(byte[], decode)的方式来还原这个“深”字时&#xff0c;这个new String(byte[],…

【UML用户指南】-07-对基本结构建模-公共机制

目录 1、术语和概念 1.1、注解&#xff08;note&#xff09; 1.2、修饰 1.3、衍型 1.4、标记值 1.5、约束 1.6、标准元素 1.7、外廓&#xff08;profile&#xff09; 2、对新特性建模 3、对新语义建模 注解 &#xff08;note&#xff09;是附加在元素或元素集上用来表…

EcoVadis审核方法是什么符合EcoVadis规范的文件清单

EcoVadis审核方法是参照全球契约社会责任国际标准进行&#xff0c;包括环境、劳工及人权、商业道德、可持续采购等四大主题又分:能源消耗及温室气体排放、水环境管理、生态环境与物种多样性保护、局部环境污染、原材料及化学品使用(含废弃物)、产品使用、产品生命末期、消费者健…

控制应优先

先从大体上的去找规律&#xff0c;然后才是数字归纳&#xff08;更为详细的&#xff09;&#xff0c;同时控制关系应该优先&#xff08;这里是天数和位置&#xff09;。是否涉及所有对象不是广泛&#xff0c;如果是具体的数值就不是广泛。

天润融通携手好丽友,打造食品零售行业智能客服新标杆

AI大模型&#xff0c;如何给食品零售行业的客服服务带来质变&#xff1f; 在很多人印象中&#xff0c;食品零售行业是不需要客户服务的。 因为绝大多数食品都是通过经销商、零售商、商场这样的渠道进行销售。所以在食品零售行业&#xff0c;一直都有一句话&#xff0c;叫“渠…

贝加莱工控机维修5PC810.SX01-00 APC810系列

工控机维修常见故障:工控机无显示、自检不过、死机、触摸不灵、按键无法操作、与PLC通讯不上驱动器报过流过载、电压高、编码器错误 等。 PLC有输入无输出、报错等工控机维修常见故障现象 。 贝加莱工控机维修常见故障排查&#xff1a; 电源灯亮但工控机没有反应&#xff1a; …

ChatTTS:对话式文本转语音模型,开源啦!突破开源语音天花板...

最近&#xff0c;一个名为 ChatTTS 文本转语音项目爆火出圈&#xff0c;短短三天时间&#xff0c;在 GitHub 上已经斩获了 9.2 k 的 Star 量。 ChatTTS&#xff1a;对话式文本转语音模型 项目地址&#xff1a;https://github.com/2noise/ChatTTS/tree/main 体验地址&#xff1a…

Houdini pbd_constraints.h的文件位置

Houdini安装目录下的houdini\vex\include文件夹 C:\Program Files\Side Effects Software\Houdini 19.5.716\houdini\vex\include

Codeforces Round 950 (Div. 3)(A~E题解)

这场比赛我自己打的是真的垃圾&#xff0c;也是侥幸被拿下了&#xff0c;第三题当时没想清楚&#xff0c;要不然还能止损一下&#xff0c;惜败惜败 话不多说&#xff0c;现在来看A~E题的题解 A. Problem Generator 题解&#xff1a;这题水题一个&#xff0c;我们来考虑本题的…

学会 YOLOv8 直接上手 YOLOv10 | YOLOv8 YOLOv10 模型结构 Yaml 文件对比

先来对比下 模型 yaml 文件&#xff0c; YOLOv8 的 5 个模型尺寸是写到一起的&#xff0c;也就是说&#xff0c;YOLOv8 的 5个尺寸之间就是宽度和深度等比例缩放&#xff1b; YOLOv10 的 6 个模型尺寸是分开写的&#xff0c;10 并不是简单的宽度和深度等比例缩放&#xff0c;…

正邦科技七:pycharm的使用

Pycharm的使用 1&#xff1a;下载python解释器&#xff1a;https://www.python.org/downloads/windows/ 2&#xff1a;下载Pycharm社区办&#xff1a;去官网下载&#xff08;不需要跟Java一样配置jdk这种环境&#xff09; 需要注意一点如果是别人发的包解压之后不能直接用&…

C++期末复习

目录 1.基本函数 2.浅拷贝和深拷贝 3.初始化列表 4.const关键字的使用 5.静态成员变量和成员函数 6.C对象模型 7.友元 8.自动类型转换 9.继承 1.基本函数 &#xff08;1&#xff09;构造函数&#xff0c;这个需要注意的就是我们如果使用类名加括号&#xff0c;括号里面…

Spring Cloud系列——使用Sentinel进行微服务保护

文章目录 一、引言1. 雪崩问题的产生原因2. 解决雪崩问题的思路 二、微服务保护1. 服务保护方案1.1 请求限流1.2 线程隔离1.3 服务熔断 2. Sentinel2.1 安装2.2 微服务整合2.2.1 请求限流2.2.2 线程隔离①OpenFeign整合Sentinel②配置线程隔离 2.2.3 服务熔断①编写降级逻辑②配…

实验室类管理平台LIMS系统的ui设计实例

实验室类管理平台LIMS系统的ui设计实例

基于STM32的位置速度环PID控制伺服电机转动位置及程序说明

PID控制原理 PID控制原理是一种广泛应用于工业自动化和其他领域的控制算法。PID控制器的名字来源于其三个主要组成部分&#xff1a;比例&#xff08;Proportional&#xff09;、积分&#xff08;Integral&#xff09;和微分&#xff08;Derivative&#xff09;。PID控制器实现…

一种一维时间序列信号的广义小波变换方法(MATLAB)

地震波在含油气介质中传播时&#xff0c;其高频分量往往比低频分量衰减更快。据此&#xff0c;地震波的高频分量和低频分量之间的差异值可以用于分析含油气衰减位置&#xff0c;从而间接指示出含油气储层。对于时频域中的地震波衰减分析&#xff0c;一般地&#xff0c;利用地震…

WebService的配置

如果提示”对操作“XXX”的回复消息正文进行反序列化时出错 那么多半是因为字符长度不够 调整参数 maxStringContentLength"10485760" maxReceivedMessageSize"2147483647" maxBufferSize"2147483647" 示例&#xff1a; messageVersion&qu…

Stable diffusion采样器详解

在我们使用SD web UI的过程中&#xff0c;有很多采样器可以选择&#xff0c;那么什么是采样器&#xff1f;它们是如何工作的&#xff1f;它们之间有什么区别&#xff1f;你应该使用哪一个&#xff1f;这篇文章将会给你想要的答案。 什么是采样&#xff1f; Stable Diffusion模…