这是一篇菜鸡的算法小笔记!希望你喜欢!

前言

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

预处理

这里就不赘述什么是回文串了!我相信你知道的!
由于回文串的长度可以是奇数也可以是偶数!要预处理一下,统一变成奇数,方法是在每一个字符的左右都加上一个特殊字符,比如加上 ‘#’。该字符是原字符串没出现过的。
例如:
fevef --> #f#e#v#e#f#
aba --> #a#b#a#
预处理后无论原字符串长度是奇数还是偶数,得到的字符串的长度都是奇数。这样就不用分情况讨论了!统一处理!
一般为防止越界,我们都会字符串的最前面和最后面再各加上一个其他的特殊字符,比如’$’ 、’^’。

回文子串的半径

我们需要一个和预处理后所得到的字符串 s 长度大小的辅助数组 p 来记录回文子串的半径!
p[i] 表示 s[i] 为中心的最长回文子串的半径。
例子:
# f # e # v # e # f #
1 2 1 2 1 6 1 2 1 2 1
然后你会惊奇地发现,p[i]-1就是以 s[i] 为中心的最长回文子串在原字符串的长度。
比如这里的p[5]=6,中心字符是v,整个最长回文串的长度是2*p[5]-1,因为每个原生字符的两边都有特殊字符,所以在回文子串中特殊字符的个数肯定比原生字符的个数多一个,即特殊字符的个数为p[5],原生字符的个数为p[5]-1。所以该回文子串在原字符串中的长度就为p[5]-1。这是个普遍的规律!

在求出所有的p[i]后,我们的问题就转化成了:求以最大 p[i] 所对应的 s[i] 为中心的最长回文子串!

求出记录回文子串半径的辅助数组p

朴素的计算方法是以一个字符为中心,向两边拓展,直到两边的字符不相同!但这不是我们需要的!

我们有一个更好的方法!这个求p数组的方法感觉跟KMP算法求next数组的方法是有相通之处的。不需要一个一个地去匹配,而是利用前面已知的信息来更好地求出辅助数组。
我们需要两个辅助变量:mx 和 id

mx 表示 已遍历所得到的回文子串中能延伸到的最右端的位置
id 表示 最右端能延伸到mx位置的回文子串的中心位置

因为 mx 是我们已知的能延伸到的最右端的位置,而我们是要利用前面已知的信息的并且 mx 位置之前的信息,我们都是可以利用的。那么我们就要尽可能去最大化 mx。

注意:下标为 mx 的字符并不包含在回文子串里

感觉可能有点绕,举个例子说明一下!
例子:
# f # e # v # e # f #
1 2 1 2 1 6 1 2 1 2 1
mx初始化为 -1,id也初始化为 -1。

遍历过程中,出现mx > i 时,如下图所示:

因为回文串是左右两边对称的,所以在求 p[i] 的时候我们就可以利用这一性质更快的求得结果。这里的 id 和 mx 都应该的已知的,也就是利用了前面已知的信息,实现优化!

精髓代码:

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

简单来说就是 mx > i 时,以 i关于id的对称点 j 为中心位置的最长回文子串被包含在 mx 的对称点到 id 这个区间时 ,那么根据对称的性质,肯定 p[i] >=p[2*id-i] 的。如果超出了这个区间,那么我们只能明确直到区间内的,区间外的我们并不能明确知道,则 p[i] >= mx - i 的。然后就可以再用朴素的方法去向左右两边拓展。

while (s[i - p[i]] == s[i + p[i]]) {//朴素的匹配方法,向左右两边扩展 p[i]++;
}

当 mx <= i 时,我们已有的信息并不能帮到什么,直接 p[i] = 1 (因为单个字符本身就是回文) 然后就只能乖乖的使用朴素的匹配方法。

具体实现代码:

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;string str;    //原字符串
string ans_str;//最长回文字符串string deal(string s) {//预处理     //abbbafhksksikiaaastring str = "$";//加上一个原有字符串中不存在的字符,防止越界for (int i = 0; i < s.length(); i++) {str += '#';str += s[i];}str += '#';str += '^';//加上一个原有字符串中不存在的字符,防止越界return str;
}
void Manacher(string str) {string s=deal(str);int* p = new int[s.length()];p[0] = 1;p[s.length() - 1] = 1;int max_pos = -1;//最长回文子串的中心位置int max_len = -1;//最长回文子串的长度int mx = 0;//已遍历所得到的回文子串能延伸到的最右端的位置,注意该索引下的字符并不包含在回文子串里int id=-1;//最右端能延伸到mx位置的回文子串的中心位置for (int i = 1; i < s.length()-1; i++) {if (mx > i) p[i] = min(p[2 * id - i], mx - i);//i在已有条件下所能延伸到的最右端的位置的左边,可由对称的性质求出else p[i] = 1;//i不在已有条件下所能延伸到的最右端的位置的左边,因为单个字符自身也是回文的,置为1,再使用朴素的匹配方法求出while (s[i - p[i]] == s[i + p[i]]) {//朴素的匹配方法,向左右两边扩展 p[i]++;}if (mx < i + p[i]) {//更新在已有条件下所能延伸到的最右端的位置和延伸到mx位置的回文子串的中心位置id = i;mx = i + p[i];}if (max_len < p[i]-1) {//更新最长回文子串的中心位置和最长回文子串的长度max_pos = i;max_len = p[i] - 1;}}ans_str = str.substr((max_pos - p[max_pos]) / 2, max_len);//最长回文子串
}
int main() {while (cin >> str) {Manacher(str);cout << "最长回文子串:" << ans_str << endl;}return 0;
}

PS:希望对你有帮助!

Manacher(马拉车)算法—简略讲解相关推荐

  1. 【算法】Manacher(马拉车)算法

    原jekyll 2019-09-07 Manacher's Alogrithm,中文名叫马拉车算法,是一位叫Manacher的人在1975年提出的一种算法,解决的问题是求最长回文子串,算法的神奇之处就 ...

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

    终于把马拉车算法搞明白了!赶紧记录一下. 这个算法用于查找一个字符串的最长回文子串 马拉车算法依次给数组p[i]赋值,马拉车算法的本质就是在每次给数组p[i] 赋值时尝试进行偷懒 例如,当要给p[6] ...

  3. manacher马拉车算法

    算法讲解 算法讲解1 #include <iostream> #define maxn 10e+6; using namespace std; char s[maxn],str[maxn* ...

  4. (manacher)马拉车算法专题题目

    manacher算法用来求解回文串问题,时间复杂度为O(n). 不懂的先可以去练习下模板板子题,求最长回文串 传送门P3501 [POI2010]ANT-Antisymmetry 这一题他给的是一个新 ...

  5. Manacher (马拉车)算法

    Manacher于1975年发现了一种线性时间算法,可以在列出给定字符串中从任意位置开 始的所有回文子串.同样的算法也可以在任意位置查找全部极大回文子串,并且时间复杂 度是线性的.那他是怎样实现的呢, ...

  6. 什么是Manacher(马拉车)算法-java代码实现

    截止到目前我已经写了 500多道算法题,其中部分已经整理成了pdf文档,目前总共有1000多页(并且还会不断的增加),大家可以免费下载 下载链接:https://pan.baidu.com/s/1hj ...

  7. Manacher(马拉车算法)

    对应letecode链接: https://leetcode-cn.com/problems/longest-palindromic-substring/ 题目描述: 给你一个字符串 s,找到 s 中 ...

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

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

  9. 《算法笔记》中文版 - 包括数组,链表,树,图,递归,DP,有序表等相关数据结构与算法的讲解及代码实现...

    来源:专知本文为资源,建议阅读5分钟本文为你分享<算法笔记>中文版. https://github.com/Dairongpeng/algorithm-note 目录概览 第一节 复杂度. ...

最新文章

  1. Docker环境下报错:unknown group ‘mlocate‘ in statoverride file E: Sub-process /usr/bin/dpkg
  2. 21.Odoo产品分析 (三) – 人力资源板块(2) – 工时表(1)
  3. SAP Cloud for Customer Price-计价简介 1
  4. 天线接收功率计算公式_对讲机天线到底有多重要?通信效果好不好全靠它了!...
  5. jenkins+svn+maven+ssh 部署配置详细记录
  6. “远程桌面己停止工作”的解决方法
  7. The file “XXX.app” couldn’t be opened because you don’t have permission to view it.问题修复...
  8. proc文件系统探索 之 以数字命名的目录
  9. 系统分析师教程(张友生)高清pdf下载
  10. 电网调度计算机系统目前有三种,电力系统知识问答(三)
  11. 用u盘如何安装linux系统,详细教您如何使用u盘安装Linux系统
  12. html字体播放,Html 字体
  13. 单代号网络图计算例题_一表多图(表格/横道图/网络图)让计划编制效率提高10倍...
  14. 使用浏览器检查工具下载网页视频
  15. 智能工厂仓库管理系统软件有哪些哪家好呢
  16. meanshift跟踪算法
  17. 【LeetCode每日一题】——LCP 44.开幕式焰火
  18. 在“动物杂交:新视野”中快速赚钱的9种方法
  19. C++检测键盘某键是否按下
  20. 如何在网站中加入qq咨询

热门文章

  1. SpinalHDL roundRobin注解
  2. execution表达式
  3. ManagementClass类|获取系统硬件配置
  4. win7驱动程序未经签名可以使用吗_Win7禁用驱动程序签名强制的方法
  5. IE9的 InPrivate 和 SmartScreen 功能大揭秘
  6. Win32 线程池 QueueUserWorkItem
  7. 思科设备配置路由重发布
  8. 一文了解均方根误差与方差、标准差的异同
  9. kali linux arp欺骗钓鱼wifi
  10. IBM朱近之:服务助云计算在中国落地