前言:
要弄懂马拉车算法,你需要一张A4纸和一支笔,然后按照我的算法步骤,自己写写画画就能弄懂(这个应该比kmp算法简单吧?


马拉车的解决的问题:
给定字符串S,求S中的最长回文子串?
解释:回文串就是正读反读都一样的字符串,比如奇回文串(bab)、偶回文串(noon)。


马拉车算法步骤:

  • 1)由于回文串存在奇回文串和偶回文串,马拉车算法第一步就是:预处理字符串,做法是在每一个字符的左右都加上一个特殊字符(前提是这个字符在字符串没有出现过),使这两种回文串都变成偶回文串。比如加上’#’,这样奇回文串(bab)还是会变成奇回文串(#b#a#b#),偶回文串(noon)会变成奇回文串(#n#o#o#n#)。

  • 2)然后我们定义一个辅助数组p用来表示经过与处理过的新字符串t,其中p[i]表示以字符t[i]为半径的回文子串长度,例如:
index 0 1 2 3 4 5 6 7 8 9 10 11 12 13
char $ # 1 # 2 # 2 # 1 # 2 # 2 #
R 1 2 1 2 5 2 1 6 1 2 3 2 1

  • 3)找规律

规律①:最大半径减1等于最长回文串的长度
看上面那个例子,以中间的 ‘1’ 为中心的回文子串 “#2#2#1#2#2#” 的半径是6,而未添加#号的回文子串为 “22122”,长度是5,为半径减1。这是个普遍的规律么?我们再看看之前的那个 “#b#o#b#”,我们很容易看出来以中间的 ‘o’ 为中心的回文串的半径是4,而 "bob"的长度是3,符合规律。再来看偶数个的情况 “noon”,添加#号后的回文串为 “#n#o#o#n#”,以最中间的 ‘#’ 为中心的回文串的半径是5,而 “noon” 的长度是4,完美符合规律。所以我们只要找到了最大的半径,就知道最长的回文子串的字符个数了。只知道长度无法定位子串,我们还需要知道子串的起始位置。


规律②:最长回文字符的起始位置是中间位置减去半径在除以2
我们还是先来看中间的 ‘1’ 在字符串 “#1#2#2#1#2#2#” 中的位置是7,而半径是6,貌似 7-6=1,刚好就是回文子串 “22122” 在原串 “122122” 中的起始位置1。那么我们再来验证下 “bob”,“o” 在 “#b#o#b#” 中的位置是3,但是半径是4,这一减成负的了,肯定不对。所以我们应该至少把中心位置向后移动一位,才能为0啊,那么我们就需要在前面增加一个字符,这个字符不能是#号,也不能是s中可能出现的字符,所以我们暂且就用美元号吧,毕竟是博主最爱的东西嘛。这样都不相同的话就不会改变p值了,那么末尾要不要对应的也添加呢,其实不用的,不用加的原因是字符串的结尾标识为 ‘\0’,等于默认加过了。那此时 “o” 在 "$#b#o#b#"中的位置是4,半径是4,一减就是0了,貌似没啥问题。我们再来验证一下那个数字串,中间的 ‘1’ 在字符串 "$#1#2#2#1#2#2#" 中的位置是8,而半径是6,这一减就是2了,而我们需要的是1,所以我们要除以2。之前的 “bob” 因为相减已经是0了,除以2还是0,没有问题。再来验证一下 “noon”,中间的 ‘#’ 在字符串 "$#n#o#o#n#" 中的位置是5,半径也是5,相减并除以2还是0,完美。所以,最长回文字符的起始位置是中间位置减去半径在除以2。


  • 4)p数组求解

关于p数组的求解,需要建立两个辅助变量mx和id,id表示回文串的中心位置下标,mx表示回文串右边最大半径下标,所以mx = id + p[id]

接下来就是求p[i],当然这也是算法中最重要的部分:

p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;

注: 2 * id - i表示 i 关于 id 对称的坐标点j。因为 j 到 id 之间到距离等于 id 到 i 之间到距离(id - j = i - id),所以j = 2 * id - i

如果 mx > i, 则 p[i] = min( p[2 * id - i] , mx - i );否则,p[i] = 1。

①: 在mx > i的前提下,若p[j] < mx - i,表示以 S[j] 为中心的回文子串包含在以 S[id] 为中心的回文子串中,由于 i 和 j 对称,以 S[i] 为中心的回文子串必然包含在以 S[id] 为中心的回文子串中,所以必有 P[i] = P[j]。

②: 在mx > i的前提下,若 p[j] >= mx - i表示以 S[j] 为中心的回文子串不一定完全包含于以 S[id] 为中心的回文子串中,也就是说p[j]表示的回文串半径超过mx对称点的坐标了,那么此时不能利用对称性了,但我们一定可以扩展到 mx 的,至于mx之后的部分我们任然需要匹配了。

③: 在mx <= i的前提下,p[i] = 1,因为此时我们需要通过中心扩展法一步一步扩展半径就行了。


关于p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;的更好理解,大家可看:一文让你彻底明白马拉车算法此文中的三种特殊情况!


  • 5)马拉车算法代码如下:
#include <vector>
#include <iostream>
#include <string>using namespace std;string Mannacher(string s)
{//插入"#"string t="$#";for(int i=0;i<s.size();++i){t+=s[i];t+="#";}vector<int> p(t.size(),0);//mx表示某个回文串延伸在最右端半径的下标,id表示这个回文子串最中间位置下标//resLen表示对应在s中的最大子回文串的半径,resCenter表示最大子回文串的中间位置int mx=0,id=0,resLen=0,resCenter=0;//建立p数组for(int i=1;i<t.size();++i){p[i]=mx>i?min(p[2*id-i],mx-i):1;//遇到三种特殊的情况,需要利用中心扩展法while(t[i+p[i]]==t[i-p[i]])++p[i];//半径下标i+p[i]超过边界mx,需要更新if(mx<i+p[i]){mx=i+p[i];id=i;}//更新最大回文子串的信息,半径及中间位置if(resLen<p[i]){resLen=p[i];resCenter=i;}}//最长回文子串长度为半径-1,起始位置为中间位置减去半径再除以2return s.substr((resCenter-resLen)/2,resLen-1);
}int main()
{cout<<Mannacher("12212")<<endl;cout<<Mannacher("122122")<<endl;cout<<Mannacher("noon")<<endl;system("pause");
}

reference:马拉车算法

马拉车算法(不懂问我)相关推荐

  1. LeetCode 第 58 场力扣夜喵双周赛(动态规划、马拉车算法,前后缀处理)/ 第 253 场力扣周赛(贪心,LIS)

    第 58 场力扣夜喵双周赛 两道600多 5193. 删除字符使字符串变好 题目描述 一个字符串如果没有 三个连续 相同字符,那么它就是一个 好字符串 . 给你一个字符串 s ,请你从 s 删除 最少 ...

  2. 马拉车算法(manacher)求最长回文子串

    关于回文字符串的概念大家可以大致去搜索一下,这里不赘述. 一.解题思路 当前字符串 最长回文子串: 思路实际上很简单,就是遍历每一个元素,然后分别以这个元素为中心,向两边扩展,比如说现在i = 4,那 ...

  3. 1616: 最长回文串(马拉车算法)

    1616: 最长回文串 Time Limit: 1 Sec Memory Limit: 128 MB [Submit][Status][Web Board] Description 求一个字符串的最长 ...

  4. 最长回文 HDU - 3068(求最长回文串的长度【马拉车算法Manacher】)

    马拉车算法 Manacher's Algorithm 是用来查找一个字符串的最长回文子串的线性方法,由一个叫 Manacher 的人在 1975 年发明的,这个方法的最大贡献是在于将时间复杂度提升到了 ...

  5. Manacher's Algorithm 马拉车算法(最长回文串)

    这个马拉车算法Manacher's Algorithm是用来查找一个字符串的最长回文子串的线性方法,由一个叫Manacher的人在1975年发明的,这个方法的最大贡献是在于将时间复杂度提升到了线性,这 ...

  6. 【HDU - 3068】最长回文(Manacher算法,马拉车算法求最长回文子串)

    题干: 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.  回文就是正反读都是一样的字符串,如aba, abba等 Input 输入有多组case,不超过120组 ...

  7. 【回文串1 动态规划 马拉车算法】LeetCode 5. Longest Palindromic Substring

    LeetCode 5. Longest Palindromic Substring LeetCode中与回文串相关的免费的题目共有15道(5, 9, 125, 131, 132, 214, 234, ...

  8. 字符串-Manacher算法(你知道马拉车算法吗?)

    文章目录 原理 奇偶问题 p[]数组 马拉车求p[] 模板 例题 P3805 [模板]manacher算法 P1659 拉拉队排练 原理 马拉车算法当然不是马拉着车的奇奇怪怪的东西,是Manacher ...

  9. leetcode-回文字符串(马拉车算法模板)

    马拉车算法 由于看了一个巨巨的博客深受启发.所以不再赘述. 巨巨的博客 leetcode-最长回文字符串: 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示 ...

  10. Manacher Algorithm马拉车算法详解

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

最新文章

  1. 高度平衡二叉树的构建_平衡二叉树建立及其增删改查(JAVA)
  2. BugkuCTF-Misc:隐写2
  3. 将 Windows10 中的 WSL 添加至右键菜单
  4. 新华字典mysql_JAVA面试(1)Mysql
  5. scrapy学习资料汇总
  6. 如何在 ASP.NET Core 中发送邮件
  7. 怎么用git将本地代码上传到远程服务器_git之如何把本地文件上传到远程仓库的指定位置...
  8. 远程桌面端口修改批处理
  9. 基于JAVA+SpringBoot+Mybatis+MYSQL的足球联赛管理系统
  10. 话说 Oracle ACE 这回事儿
  11. OpenGL超级宝典 渲染管线(二)
  12. openCV4+vs2019环境搭建
  13. mysql批量导出导入数据
  14. python 自动化合并 ts 视频流
  15. 标题中冒号的用法_如果论文题目中出现冒号,冒号前后两部分内容通常是?
  16. Jenkins - Publish Over SSH
  17. 3 idiots的台词
  18. uni-app背景图片 background-image,支持 base64 格式图片、支持网络路径图片、本地路径背景图片
  19. AI赋能下的声纹识别技术在公共安全领域的深度应用
  20. 办公局域网内的打印机如何做共享?

热门文章

  1. java 定时任务的实现_Java定时任务实现的几种方式
  2. 使用WePE对无法启动的系统文件进行操作
  3. yuv420p 详解_YUV格式详解,图文详解YUV420数据格式
  4. java 图片转pdf_在Java语言中将图像转换为PDF?Spire.PDF for Java轻松搞定!
  5. 新宝资讯上证涨跌比:1131:649
  6. 2022年2月份报告合集(共326份)
  7. vga分辨率与时序配置
  8. 最大流最小割经典例题_图像分割之最小割与最大流算法
  9. Drools4.0官方使用手册中文
  10. 布客·ApacheCN 编程/后端/大数据/人工智能学习资源 2020.6