对应letecode链接:

https://leetcode-cn.com/problems/longest-palindromic-substring/

题目描述:

给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:

输入:s = "cbbd"
输出:"bb"
示例 3:

输入:s = "a"
输出:"a"
示例 4:

输入:s = "ac"
输出:"a"

首先回文串有两种形式:

一种是奇数的比如"aba",一种是偶数的比如"abba"

如果我们单个字符为中心向两边扩散在这种情况下就会出现问题长度为偶数的回文:"abba"

首先我们以首字符a为中心向两边扩散得得到的最长回文字串的长度为1也就是a.我们在已下一个字符b为中心括的时候长度也为1下一个b为中心括的时候长度也为1最终我们求到的最长长回文字串的长度为1.但实际上字符串本身就是回文字符串这是因为他的对称轴是在一个虚的位置。     

Manacher为了解决这个问题会在每个字符之间都会插入一个特殊字符,并且两边也会插入,这个特殊字符要保证不能是原字符串中的字符,这样无论原来字符串长度是奇数还是偶数,添加之后长度都会变成奇数。例如:

“#a#b#a#"(长度为7)

"#a#b#b#a#(长度为9)

在这里所加入的特殊字符要不要求是原串中没有出现的字符呢?答案是并不一定。特殊字符是可以随意。这是为什么因为在括散的过程中因为不会出现特殊字符和原来字符串中的字符相比较的情况。特殊字符只是起到辅助作用不会影响到最终的结果

在这里我们引入一个变量叫回文半径,通过添加特殊字符,原来字符串长度无论是奇数还是偶数最终都会变为奇数,因为特殊字符的引用,改变之后的字符串的所有回文子串长度一定都是奇数。并且回文子串的第一个和最后一个字符一定是你添加的那个特殊字符。其实很好证明

如果原来回文子串的长度是奇数,通过中间插入特殊字符,特殊字符的个数必定是偶数,在加上两边的特殊字符,长度必然是奇数

如果原来回文子串的长度是偶数,通过中间插入特殊字符,特殊字符的个数必定是奇数,在加上两边的特殊字符,长度必然是奇数

因为添加特殊字符之后所有回文子串的长度都是奇数,我们定义回文子串最中间的那个字符到回文子串最左边或者最右边的长度叫回文半径。

比如字符串"babad"在添加特殊字符之后每个字符的回文半径:

搞懂了这个我们再来看一下最长回文子串该怎么求。在上面我们讲过中心扩散法,我们会以每一个字符(中间会过滤掉重复的)为中心往两边扩散,如果以当前字符为中心往两边扩散计算完的时候,到下一个字符在往两边扩散的时候还要重新计算,那么有没有一种方法不用重新计算,而利用之前计算的结果呢,答案是肯定的。

假设当前字符s[maxCenter]为回文中心的最大回文长度为是从left到maxRight如果我们想求以字符s[i]为回文中心的最大回文长度,我们只需要找到i关于maxCenter的对称点j,看下j的回文长度,因为j已经计算过了。

有以后三种情况:

1.i在maxRight的左边并且以i关于maxCenter的对称点j 为回文中心的回文区域在leftmaxRight之内。

2.i在maxRight的左边并且以i关于maxCenter的对称点j为回文中心区域最大回文长度的左边刚好到达left或者超过left

3.如果i在maxRight的右边

情况一:i在maxRight的左边并且以i关于maxCenter的对称点j 为回文中心的回文区域在leftmaxRight之内。

为什什么i对应的回文半径就等于j对应的回文半径呢?通过对称性可知以i的回文半径至少是以j为回文中心的半径为什不能在大了?证明:假设已j为回文中心区域左边界的前一个字符为x,右边界的后一个字符为y,已i为回文中心区域左边界的前一个字符为z,右边界的后一个字符为L。这时就有当时为什么已j为回文中心的区域没能括的更大了原因只可能是x!=y由对称关系可得z==y,x==L。所以我们可以推出z!=L证毕。

情况二:

i在maxRight的左边并且以i关于maxCenter的对称点j为回文中心区域最大回文长度的左边刚好到达left或者超过left。如果是超过left那么对应i对应的回文半径为maxRight-i,如果刚好到达left那么对应回文半径的答案至少为maxRight-i是否能够更大就要看maxRight-i的前一个字符和maxRight+i是否相等如果相等那么就能够更长

情况三:

3.如果i在maxRight的右边

在这种情况下我们无法利用之前计算的结果,此时我们只能暴力扩

对应代码:

class Solution {
public:string longestPalindrome(string s)
{int len = s.length();if (len < 1){return "";}// 预处理string s1;for (int i = 0; i < len; i++){s1 += "#";s1 += s[i];}s1 += "#";len = s1.length();int MaxRight = 0;             // 当前访问到的所有回文子串,所能触及的最右一个字符的下一个位置int Center = 0;                    // MaxRight对应的回文串的对称轴所在的位置int MaxRL = 0;                   // 最大回文串的回文半径int MaxCenter = 0;                    // MaxRL对应的回文串的对称轴所在的位置int* RL = new int[len];         // RL[i]表示以第i个字符为对称轴的回文串的回文半径memset(RL, 0, len * sizeof(int));for (int i = 0; i < len; i++){RL[i]=MaxRL>i?min(RL[2*Center-i],MaxRL-i):1;//将上序三种情况合并// 尝试扩展RL[i],注意处理边界while (i - RL[i] >= 0  // 可以把RL[i]理解为左半径,即回文串的起始位不能小于0&& i + RL[i] < len // 同上,即回文串的结束位不能大于总长&& s1[i - RL[i]] == s1[i + RL[i]]// 回文串特性,左右扩展,判断字符串是否相同){RL[i]++;}// 更新MaxRight, posif (RL[i] + i  > MaxRight){MaxRight = RL[i] + i ;Center = i;}// 更新MaxRL, MaxPosif (MaxRL <RL[i]){MaxRL = RL[i];MaxCenter = i;}}return s.substr((MaxCenter-MaxRL+1) / 2, MaxRL - 1);//返回字串
}
};

Manacher(马拉车算法)相关推荐

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

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

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

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

  3. Manacher(马拉车)算法—简略讲解

    这是一篇菜鸡的算法小笔记!希望你喜欢! 前言 马拉车算法是用来查找一个字符串的最长回文子串的线性方法,是一个叫 Manacher 的人在 1975 年发明的,这个方法的最大贡献是在于将时间复杂度提升到 ...

  4. manacher马拉车算法

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

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

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

  6. Manacher (马拉车)算法

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

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

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

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

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

  9. 最长回文串 马拉车算法 C++

    最长回文串 LeetCode 5.最长回文串 给你一个字符串 s,找到 s 中最长的回文子串. 示例 1: 输入:s = "babad" 输出:"bab" 解释 ...

最新文章

  1. flyway配置mysql_SpringBoot 中的Flyway配置
  2. TeX下的Markdown包
  3. centos 6.5 rpm mysql_Linux平台(CentOS 6.5) RPM包方式安装 Mysql 5.7
  4. burpsuite小米手机抓包_使用burpsuite实现Android APP的HTTPS抓包
  5. 脉位调制解调 matlab,通信原理与matlab仿真v2 第五章 DBPSK调制解调器(1)
  6. 沃顿商学院最受欢迎的思维课
  7. (15)System Verilog系统随机函数
  8. aws iam php,php-AWS4签名密钥-本教程错误吗?
  9. 如何在没有原工程的情况下,利用vivado将bit文件转化成bin文件
  10. v5服务器装系统,小白必学:宏基V5-591G内存、固态、装系统教程!
  11. 【开发工具】【Bus Hound】USB抓包工具(Bus Hound)的使用
  12. 转录组和蛋白质组结合分析-入门笔记
  13. DS博客作业06——图
  14. 【深度学习】2.1深度学习的实用层面
  15. AlphaGo Zero 初探
  16. halcon第七讲:基于训练学习的颜色检测
  17. 徒手攀登酋长岩,世界第一人!
  18. 【ThinkPad系统重装】
  19. STM32 USB基础知识
  20. java后台 重置手机密码(邮箱点击确认)

热门文章

  1. String字符串反转
  2. VNC Linux 远程桌面控制软件
  3. Android语音播报、后台播报、语音识别,android面试知识点
  4. 在 Linux 上安装软件的 3 种方法
  5. 如何在Flash里面使用魔术棒工具
  6. Github桌面版安装和汉化
  7. 结合分析【spss】
  8. 基于51单片机随机数自动摇号抽奖系统Proteus仿真
  9. 传奇开服需要多少钱?传奇服务端建立不了行会,传奇开区时点创建行会没反应的解决方法
  10. Electron - 用前端的技术开发桌面应用(二)