Manacher马拉车算法求最长回文子串

Manacher马拉车算法求最长回文子串终于把马拉车算法搞明白了 赶紧记录一下 以后忘记了还能再回忆起来 这个算法用于查找一个字符串的最长回文子串马拉车算法依次给数组 p i 赋值 马拉车算法的本质就是在每次给数组 p i 赋值时尝试进行偷懒 例如 当要给 p 6 赋值时 前面分别以 p 0 p 1 p 2 p 3 p 4 p 5 为中心的回文子串都已经找出来了 而且这六个回文子串中的 nbsp 最长的回文子串

终于把马拉车算法搞明白了!赶紧记录一下,以后忘记了还能再回忆起来。

这个算法用于查找一个字符串的最长回文子串

马拉车算法依次给数组p[i]赋值,马拉车算法的本质就是在每次给数组p[i] 赋值时尝试进行偷懒

例如,当要给p[6]赋值时,前面分别以 p[0],p[1],p[2],p[3],p[4],p[5]为中心的回文子串都已经找出来了,
而且这六个回文子串中的   最长的回文子串  和  最靠近右端的回文子串  也找出来了。

如果这个最靠近右端的回文子串特别长的话(怎么个长法,这是有条件的,看后文),

在找以p[6]为中心的回文子串时就可以偷懒了!哈哈!

一个小插曲,讲个小故事。要结合我下面的两个条件1和2哦!
说有一个洋葱,里面的某一层有一个虫子。要找到这个虫子就得一层一层的找。我们知道剥洋葱是从外面往里面一层一层的剥,
但是这里找虫子恰恰相反,必须从里面往外面一层一层的找。你明白了吗?
条件1是说 不好意思,咱俩的洋葱没有啥关系,所以你就得老老实实的从最里面的一层开始往外找了。

条件2是说 咱俩的洋葱m层以内完全相同,已经知道我的洋葱n层以内都没有虫子,

由此可以确定你的洋葱min{m, n}以内都没有虫子,

所以你找的时候只需要从min{m, n}+1层往外找就行了。看看,马拉车算法偷懒就在这个地方。
插曲讲完了,接着说。

1.如果这个最靠近右端的回文子串的右端点mx在i的左边,那不好意思,你前面找出来的回文子串再多,
对于我现在要找的这个以i为中心的回文子串来说没有任何帮助,但是考虑到回文子串再短也至少是一个字符吧,那就先为你赋值为1。
所以后面的while()循环语句就得老老实实的从你字符自身两边的两个字符开始向外层依次判断是否相同,然后找出这个回文子串

2.如果这个最靠近右端的回文子串的右端点mx在i的右边,嘻嘻!看来有戏!
你前面千辛万苦找出来的那个最靠近右端的回文子串对于我现在要找的这个以i为中心的回文子串来说就有帮助。

还需要借助上面的小插曲 !

说 你有一个洋葱,我有一个洋葱,咱俩的洋葱都是有10层而且5层及以内完全相同,什么意思,就是5层及以内,你的洋葱在第几层有虫子,

我的洋葱在第几层也有虫子,就是说5层及以内要有虫子都有,而且位置一样,要没有虫子都没有。

   p[2 * id – i] = 3
   mx – i = 5

   p[i] 只能取两者的最小值3  故p[i] = p[2 * id – i]

因为你的洋葱4层和5层有没有虫子不确定,那我的洋葱4层和5层也不确定,所以后面我要从第4层开始往外层找虫子。

2.2 如果你的洋葱7层及以内没有虫子,那我的洋葱5层及以内没有虫子,因为你的洋葱6层和7层和我的不一样,那我的洋葱6层和7层更加不确定了,

   p[2 * id – i] = 7
   mx – i = 5

   p[i] 只能取两者的最小值5  故p[i] = mx – i

但是咱俩5层及以内是相同的, 所以后面我要从第6层开始往外层找虫子。

#include 
                              
                                #include 
                               
                                 #include 
                                
                                  #include 
                                 
                                   using namespace std; string Manacher(string s) { // Insert '#' string t = "$#"; for (int i = 0; i < s.size(); ++i) { t += s[i]; t += "#"; } // Process t vector 
                                  
                                    p(t.size(), 0); int id = 0;//记录最靠近右端的回文子串的中心点 int mx = 0;//记录最靠近右端的回文子串的右端点 int resCenter = 0;//记录所有回文子串中最长回文子串的中心点 int resLen = 0;//记录所有回文子串中最长回文子串的长度 for (int i = 1; i < t.size(); ++i) { //p[i]获得的值越大越好,p[i]的值越大,while()函数遍历的时候不必从1开始,而是从更大的p[i]开始 //这样大大缩短的while()的执行次数,这也是马拉车算法的核心所在 p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1; //求以i为中心点的最大回文串 while (t[i + p[i]] == t[i - p[i]]) ++p[i]; //下面这个if()语句的作用是找出最靠近右端的回文子串 //如果 当前找到的这个以i为中心点的回文子串 比 上一个记录的最靠右端的回文子串还要靠近右端 //就把这个回文子串 当做 最靠近右端的回文子串 if (mx < i + p[i]) { id = i; mx = i + p[i]; } //id 和 mx 记录的是最靠近右端的回文子串的中心点和右端点,但是这个回文子串不一定是最长的回文子串 //所以用 resCenter 和 resLen 记录目前得到的最长的回文子串 //遍历到最后记录的就是要求的最长的回文子串 if (resLen < p[i]) { resLen = p[i]; resCenter = i; } } //根据处理后的最长回文子串的中心点和长度找到这个最长回文子串在原来字符串中的位置,然后输出 return s.substr((resCenter - resLen) / 2, resLen - 1); } int main() { string s1 = "edcbabcdemmnmm"; cout << Manacher(s1) << endl; system("pause"); return 0; } 
                                   
                                  
                                 
                                
                              

























































































版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/224388.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午12:03
下一篇 2026年3月17日 下午12:03


相关推荐

  • 一文读懂 Spring Bean 的生命周期「建议收藏」

    一文读懂 Spring Bean 的生命周期「建议收藏」欢迎大家关注我的微信公众号【老周聊架构】,Java后端主流技术栈的原理、源码分析、架构以及各种互联网高并发、高性能、高可用的解决方案。一、前言今天我们来说一说SpringBean的生命周期,小伙伴们应该在面试中经常遇到,这是正常现象。因为SpringBean的生命周期是除了IoC、AOP几个核心概念之外最重要概念,大家务必拿下。可Spring源代码又比较复杂,跟着跟着就不知道跟到哪里去了,不太好拿下呀。这倒是真的,而且网上一上来就各种贴流程源码,对初学者来说是真的一脸懵逼,就像字.

    2026年1月26日
    5
  • OpenClaw单机部署_OpenClaw单机部署详解

    OpenClaw单机部署_OpenClaw单机部署详解

    2026年3月13日
    2
  • Mybatis源码分析_struts源码

    Mybatis源码分析_struts源码Mybatis提供了一个简单的逻辑分页类RowBounds,其原理类似于在内存中做了一个分页,不是数据库层面的分页,性能不算好,谨慎使用一.RowBounds源码分析1RowBounds源码:/***Copyright2009-2017theoriginalauthororauthors.**LicensedundertheApacheLicense,Version2.0(the”License”);*youmaynot.

    2026年2月13日
    4
  • Python 开发 漏洞的批量搜索与利用.(GlassFish 任意文件读取)「建议收藏」

    Python 开发 漏洞的批量搜索与利用.(GlassFish 任意文件读取)「建议收藏」?Python开发学习的意义:?(1)学习相关安全工具原理.?(2)掌握自定义工具及拓展开发解决实战中无工具或手工麻烦批量化等情况.?(3)在二次开发Bypass,日常任务,批量测试利用等方面均有帮助.

    2022年8月20日
    6
  • 如何刷原生android系统版本,小米手机1原生Android4.1系统刷机教程

    如何刷原生android系统版本,小米手机1原生Android4.1系统刷机教程《小米手机1原生Android4.1系统刷机教程》由会员分享,可在线阅读,更多相关《小米手机1原生Android4.1系统刷机教程(4页珍藏版)》请在人人文库网上搜索。1、小米手机1原生Android4.1系统刷机教程各位亲爱的米粉:小米手机1原生Android4.1系统已经正式公测,小米手机1、小米手机1s及小米手机1S青春版均可升级。您可以通过卡刷与线刷两种方式升级至Androi…

    2022年6月19日
    44
  • executescalar mysql_DbCommand.ExecuteScalar 方法的返回值[通俗易懂]

    executescalar mysql_DbCommand.ExecuteScalar 方法的返回值[通俗易懂]DbCommand.ExecuteScalar方法执行查询,并返回查询所返回的结果集中第一行的第一列。所有其他的列和行将被忽略。语法:publicabstractObjectExecuteScalar()返回值:类型:System.Object,结果集中第一行的第一列。备注:使用ExecuteScalar方法从数据库中检索单个值(例如一个聚合值)。与使用ExecuteRe…

    2022年6月29日
    34

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号