Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串

Manacher算法:求解最长回文字符串,时间复杂度为O(N) Manacher算法:求解最长回文字符串,时间复杂度为O(N) 回文串定义:“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。回文子串,顾名思义,即字符串中满足回文性质的子串。 立即下载
源于这两篇文章:
http://blog.youkuaiyun.com/ggggiqnypgjg/article/details/6645824
http://zhuhongcheng.wordpress.com/2009/08/02/a-simple-linear-time-algorithm-for-finding-longest-palindrome-sub-string/

这个算法看了三天,终于理解了,在这里记录一下自己的思路,免得以后忘了又要想很久- -.

首先用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一个特殊的符号。比如 abba 变成 #a#b#b#a#, aba变成 #a#b#a#。 为了进一步减少编码的复杂度,可以在字符串的开始加入另一个特殊字符,这样就不用特殊处理越界问题,比如$#a#b#a#。

下面以字符串12212321为例,经过上一步,变成了 S[] = "$#1#2#2#1#2#3#2#1#";

然后用一个数组 P[i] 来记录以字符S[i]为中心的最长回文子串向左/右扩张的长度(包括S[i]),比如S和P的对应关系:
S   #  1  #  2  #  2  #  1  #  2  #  3  #  2  #  1  #
P   1  2  1  2  5  2  1  4  1  2  1  6  1  2  1  2  1
(p.s. 可以看出,P[i]-1正好是原字符串中回文串的总长度)

那么怎么计算P[i]呢?该算法增加两个辅助变量(其实一个就够了,两个更清晰)id和mx,其中id表示最大回文子串中心的位置,mx则为id+P[id],也就是最大回文子串的右边界。

然后可以得到一个非常神奇的结论,这个算法的关键点就在这里了:如果mx > i,那么P[i] >= MIN(P[2 * id - i], mx - i)。就是这个串卡了我非常久。实际上如果把它写得复杂一点,理解起来会简单很多:
//记j = 2 * id - i,也就是说 j 是 i 关于 id 的对称点。
if (mx - i > P[j])
    P[i] = P[j];
else /* P[j] >= mx - i */
    P[i] = mx - i; // P[i] >= mx - i,取最小值,之后再匹配更新。

当然光看代码还是不够清晰,还是借助图来理解比较容易。

当 mx - i > P[j] 的时候,以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中,由于 i 和 j 对称,以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中,所以必有 P[i] = P[j],见下图。


当 P[j] > mx - i 的时候,以S[j]为中心的回文子串不完全包含于以S[id]为中心的回文子串中,但是基于对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以S[i]为中心的回文子串,其向右至少会扩张到mx的位置,也就是说 P[i] >= mx - i。至于mx之后的部分是否对称,就只能老老实实去匹配了。


对于 mx <= i 的情况,无法对 P[i]做更多的假设,只能P[i] = 1,然后再去匹配了。

于是代码如下:
//输入,并处理得到字符串s
int p[1000], mx = 0, id = 0;
memset(p, 0, sizeof(p));
for (i = 1; s[i] != '\0'; i++) {
    p[i] = mx > i ? min(p[2*id-i], mx-i) : 1;
    while (s[i + p[i]] == s[i - p[i]]) p[i]++;
    if (i + p[i] > mx) {
        mx = i + p[i];
        id = i;
    }
}
//找出p[i]中最大的
 
 
C语言|深入浅出讲解int转换为float全过程(附2017年统考大题案例) int转换为float类型为什么会发生精度损失? 精度损失的详细过程究竟是什么样的? 什么样情况float会发生精度损失?没有弄懂2017年浮点数统考大题? 这一篇用2017年统考大题案例帮你更深的理解浮点数的存储规则。 阅读详情

相关推荐

GDSFactory环境配置实战:Python、KLayout与PDK协同指南

GDSFactory是面向光子集成电路(PIC)设计的Python参数化建模框架,其核心价值在于将版图生成从手动绘图升维为可编程、可复现、可集成CI/CD的工程实践。它依赖Python科学计算生态(如NumPy)、EDA可视化工具KLayout的深度Python绑定,以及工艺厂PDK的标准化接入,三者构成‘计算-几何-工艺’技术闭环。典型应用场景包括教学级SiEPIC PDK快速原型、工业级AIM Photonics流片准备,以及自动化DRC与光学仿真流水线构建。本文聚焦GDSFactory落地中最关键也最

weixin_30983353的博客 368

笔试面试算法经典--最长回文子串

回文的定义正读和反读都相同的字符序列为“回文”,如“abba”、“abccba”是“回文”,“abcde”和“ababab”则不是“回文”。字符串的最长回文子串,是指一个字符串中包含的最长的回文子串。例如“1212134”的最长回文子串是“12121”。下面给出了三种求最长子串的方法。解法1(中心扩展法)时间复杂度O(n^2),空间复杂度为O(1)。中心扩展法的思路是,遍历到数组的某一个元素时,以这

有图有真相 4万+

跟着Cell学单细胞转录组分析(五):单细胞转录组marker基因鉴定及细胞群注释

书接上回(跟着Cell学单细胞转录组分析(四):单细胞转录组测序UMAP降维聚类)。完成数据降维和细胞聚类后,最主要的环节和工作就是确定各个细胞群,明确是什么类型的细胞,正群的细胞定群很关键,涉及到整个研究,所以这一步宁愿多费时间,也不要出错。当然,这也不是一蹴而就的,需要反复的确认。 要确定各个群是什么细胞,首先需要了解细胞群的marker基因,因为不同类型的细胞突出 表达的基因也是不同的。这里使用FindAllMarkers鉴定各个细胞群的高表达基因。 DefaultAssay(scedata)

qq_42090739的博客 1万+

题解:最长回文子串(4种解法)

题目:最长回文子串 难度:中等 一、描述 二、题解: 2.1 暴力法(O(N^3)) 解释: 循环三次。第一次起始点循环;第二次终止点循环(从最右边开始到起始点为止);第三次起始点开始终止点结束,当两个值不相等时候跳出循环。只有完整进行第三次循环才满足回文串的条件。 class Solution: def longestPalindrome(self, s: str) -> str: max_ = 1 max_str = s[0] length

v-space的博客 2万+

YOLOv8 ultralytics使用笔记----labelme标记数据,训练模型、追踪目标。

Ultralytics是一个Python库,它是为执行高级计算机视觉任务而创建的,如对象检测、实例分割、图像分类等。Ultralytics为YOLO模型发布了一个全新的存储库,它被构建为用于机器视觉统一框架。这里先利用,并激活。

qq_48050838的博客 1万+

机械臂开发必备:KDL库正逆解与动力学实战指南

在机器人算法领域,运动学与动力学计算是机械臂控制、仿真与轨迹规划的核心基础。正运动学描述关节空间到笛卡尔空间的映射,逆运动学则需要求解复杂的非线性方程,工程实现时常面临数值稳定性与调试效率的挑战。KDL(Kinematics and Dynamics Library)作为ROS生态中广泛使用的开源库,提供了统一的模型描述与高效求解器,将正逆解、雅可比矩阵及动力学参数计算封装为简洁接口,大幅降低开发门槛。无论是机械臂的笛卡尔空间轨迹跟踪,还是基于动力学模型的前馈控制,KDL都展现出强大的工程价值。本文从运动学

weixin_33860528的博客 2505

LeetCode第五题:最长回文子串(Java)

题目:最长回文子串 示例: 输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。 这道题用到许多编程思想,中心扩展、动态规划、著名的manacher(马拉车),是前面题所没用用过的方法。 方法一:暴力循环 找到所有子串,判定是否是回文串,保存最长长度的回文串。 public static String longestPalindrome(String s) { //存储最长子串 String str = "";

巨坑的菜比的博客 1万+

ABAP - Function ALV 11 - 单元格下拉框

【代码】ABAP - Function ALV 11 - 单元格下拉框。

HeathlX的博客 1812

leetcode5. 最长回文子串

s.charAt(i)每次都会检查数组下标是否越界,所以最好先转化成字符数组 char[]arr=s.toCharArray 方法1:暴力解法: 就是暴力枚举,每截取到一个字符串就利用回文串判断函数(自己写的)来判断是不是回文串,并记录长度,输出最长的一个就好了 s.subString用起来呀 暴力解法在两个for循环中还做了遍历,因此,时间复杂度是O(n3) 方法2:枚举所有子串的可能的中心位置 中心扩散法:从中间位置开始,向两边扩散,直到不能匹配 需要分奇数长度和偶数长度,因为中心位置可能是一个字符

想握住此生辽阔 3687

从法律文档到知识图谱

这里我们定义了两个 Pydantic 模型:Location 用于捕捉结构化的地址信息,包含可选的国家、州和地址字段;Party 用于表示合同参与方,包含必填的名称和可选的位置详情。字段描述通过告知 LLM 每个字段具体需要查找哪些信息,来辅助提取过程。"""包含结构化地址组件的位置信息。"""country: Optional[str] = Field(None, description="国家")

Anspire的博客 3030

EtherCAT主站SOEM -- 0 -- 该EtherCAT主站SOEM专栏后续安排

SOEM(Simple Open EtherCAT Master)是一个开源的EtherCAT主站库,允许开发者构建自定义的EtherCAT主站应用程序。EtherCAT是一种实时以太网通信协议,广泛应用于工业自动化和机器控制领域。开源性质:SOEM是一个开源项目,这意味着开发者可以自由地查看、修改和分发代码。这使其成为工业自动化领域的一个强大工具,可以根据具体需求进行定制。EtherCAT主站实现:SOEM库提供了一个完整的EtherCAT主站实现,允许主站与多个EtherCAT从站设备进行通信。

常驻客栈的博客--嵌入式EtherCAT 6664

如何求一个字符串最长的回文子串 三种方法 思路详解

如题示例 输入:s = "ababa" 输出:"bab" 解释:"aba" 同样是符合题意的答案。 一道算法题,肯定思路最先想到的肯定是暴力解法,也是最简单的, 方法一 : 暴力破解 思路:列举字符串所有的子串,判断是否为回文数,在返回其中最大的一个 (代码已经运行通过,放心食用!) 现在我来解释一下: 这个很简单,len是代表着字符串s的长度,这里就是判断一下如果s为null或者长度为1,直接返回s就是其最大回文数了。注意一下,length()是String内一个方法,返回字符串的.

m0_65725614的博客 1万+

【YOLOv11多模态涨点改进】独家创新首发| TGRS 2026 |引入 CIFusion 通道交互融合模块,通过跨特征交互机制强化目标区域响应,适合多模态融合目标检测,小目标检测高效涨点

🔥本文提出了一种改进YOLOv11多模态目标检测模型的方法,通过引入CIFusion通道交互融合模块来提升RGB与红外特征融合效果。CIF模块采用通道级自适应交互机制,根据全局上下文动态分配不同模态通道的重要性,实现跨模态特征交互与互补信息融合。相比传统拼接或加权融合方式,CIF能够增强目标区域响应,抑制背景噪声,提高小目标和低对比度目标的检测性能。实验表明,该方法在DroneVehicle等数据集上显著提升了检测精度。论文还详细介绍了CIF模块的结构原理、实现代码及模型配置方法。

Ai缝合怪、助力小伙伴高效发论文 186

Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串 (转)

转自:http://www.felix021.com/blog/read.php?2040 源于这两篇文章: http://blog.youkuaiyun.com/ggggiqnypgjg/article/details/6645824http://zhuhongcheng.wordpress.com/2009/08/02/a-simple-linear-time-algorithm-for-fi...

Yan_18700101086的博客 150

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

上一篇: 笔试面试---设计模式&软件测试&软件工程
下一篇: 找出字符串中连续出现次数最多的子串
crazyhacking
博客等级 码龄15年 299粉丝 148原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值