Manacher's Algorithm针对的是最长回文子串问题。对于此问题,最直接的方法是遍历每一个元素,遍历过程中以每一个字符为中心向两边扩展以寻找此字符为中心的最长回文子串。复杂度O(n2)。Manacher算法将时间复杂度降至O(n),关键点在于将奇偶字串统一成奇数字串。

  方法是在每一个字符的左右都加上一个特殊字符,如'#'

  ”abccba" -> "#a#b#c#c#b#a#"

  "abcba"  -> "#a#b#c#b#a#"

  对于长度为n的字符串,需添加 n+1 个特殊字符,则新字符串长度为 2n+1。从而解决了奇偶字串分情况判断问题。

  假设原字符串为 str,添加特殊字符串后的新字符串为 trans,设立长度与 trans 相同的一个数组 p,p[i] 代表以 trans[i] 为中心的最长回文字串的半径,例如对于trans = "#a#b#c#", p[2] = 2(”#a#“), p[3] = 1(”#“)。  

  trans :# 1 # 2 # 2 # 1 # 2 # 2 #
  p       :1 2 1 2 5 2 1 6 1 2 3 2 1

  p 数组的一个性质是 p[i] - 1 即是以 trans[i](trans[i] 为原字符串中元素) 为中心的最长回文字串在原字符串S中的长度。证明:首先在转换得到的字符串 trans 中,所有的回文字串的长度都为奇数,那么对于以 trans[i] 为中心的最长回文字串,其长度就为 2*p[i]-1 ,经过观察可知,trans 中所有的回文子串,其中分隔符的数量一定比其他字符的数量多1,也就是有 p[i] 个分隔符,剩下 p[i]-1 个字符来自原字符串,所以该回文串在原字符串中的长度就为 p[i]-1。

  因为添加的特殊字符也需要搜索其最长回文字串,那么为了避免复杂的边界讨论,需要在字符串首尾各添加与之前添加的特殊字符不同的另一特殊字符作为边界。(通常只在首部添加,尾部不需要添加的原因是字符串的结尾为 '\0' ,相当于已经加过了。所以如果在某种情况下字符串没有默认的 '\0'结尾,那么需要人为的添加一个特殊字符)

  添加两个辅助变量,mx 和 id。mx是目前最长回文字串能延伸的最右位置。id 为 最长回文字串的对称轴所在位置。

  1. 当 mx > i

   最长回文字串为 (trans[2 * id - mx], trans[mx]).  i 在此最大回文字串中,j 为 i 关于 id 的对称点

    1) mx - i > p[j]

                    

    

        当 mx - i > p[j],说明 p[i] = p[j] = p[2*id - i]。因为 j 是 i 关于 id 的对称点,既然 以 j 为中心的最长回文字串都在 以 id 为中心的回文字串中,那么 以 i 为中心的回文字串也应该在以 id 为中心的回文字串中。假设 以 j 为中心的最长回文字串左端点为 begin,右端点为 end,那么由于 mx - i > p[j],所以 j - mx > p[j], 所以 begin > mx的对称点,end < id。相同的,由于以 i 为中心的回文字串也应该在 (id,mx)范围内,因为 i 和 j 都在回文串(mx对称点, mx)内,那么(mx, j)与(i,mx)相同。所以 p[i] = p[j]

    2) mx - i <= p[j]

      

        当 mx - i <= p[j] 时,以 j 为中心的回文子串不一定完全包含于以 id 为中心的回文子串中,但是基于对称性可知,图中两个绿框所包围的部分是相同的,也就是说以i 为中心的回文子串,其向右至少会扩展到 mx 的位置,也就是说 P[i] >= mx - i。至于 mx 之后的部分是否对称,只能通过遍历得知了。

  2. 当 mx <= i

    说明以 i 为对称轴的回文串还没有任何一个部分被访问过,于是只能从 i 的左右两边开始尝试扩展了,当左右两边字符不同,或者到达字符串边界时停止。然后更新 mx 和 id 。

  最长回文子串对应原串中的位置:l = (i - p[i])/2; r = (i + p[i])/2 - 2;

  

 #include <iostream>
#include <string.h>
#include <stdio.h> using namespace std;
const int N=<<; char T[N]; //原字符串
char S[N]; //转换后的字符串
int R[N]; //回文半径 void Init(char *T)
{
S[] = '$';
int len = strlen(T);
for(int i = ; i <= len; i++)
{
S[*i + ] = '#';
S[*i + ] = T[i];
}
} void Manacher(char *S)
{
int k = ,mx = ;
int len = strlen(S);
for(int i = 1; i < len; i++)
{
if(mx > i)
R[i] = R[*k - i] < mx - i? R[*k-i] : mx-i;
else
R[i] = ;
while(S[i + R[i]] == S[i - R[i]])
R[i]++;
if(R[i] + i > mx)
{
mx = R[i] + i;
k = i;
}
}
} int main()
{
while(~scanf("%s", T))
{
Init(T);
Manacher(S);
int len = strlen(S);
int ans = ;
for(int i = ; i<len; i++)
ans = R[i] > ans? R[i] : ans;
printf("%d\n", ans - );
}
return ;
}

转自:链接 ,链接

 注意:题目中的S[i + R[i]] == S[i - R[i]]实际上已经属于越界访问,但由于语言和编译器的不同,对于越界问题处理也不同。

【算法总结】Manacher's Algorithm的更多相关文章

  1. 什么是马拉车算法(Manacher's Algorithm)?

    提出问题 最长回文子串问题:给定一个字符串,求它的最长回文子串长度. 如果一个字符串正着读和反着读是一样的,那它就是回文串.如a.aa.aba.abba等. 暴力解法 简单粗暴:找到字符串的所有子串, ...

  2. 马拉车算法(Manacher's Algorithm)

    这是悦乐书的第343次更新,第367篇原创 Manacher's Algorithm,中文名叫马拉车算法,是一位名叫Manacher的人在1975年提出的一种算法,解决的问题是求最长回文子串,神奇之处 ...

  3. Manacher's Algorithm 马拉车算法

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

  4. Manacher's Algorithm(马拉车算法)

    ## 背景 该算法用于求字符串的最长回文子串长度. ## 参考文章 >[最长回文子串——Manacher 算法](https://segmentfault.com/a/1190000003914 ...

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

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

  6. Manacher's algorithm

    Manacher's algorithm 以\(O(n)\)的线性时间求一个字符串的最大回文子串. 1. 预处理 一个最棘手的问题是需要考虑最长回文子串的长度为奇数和偶数的情况.我们通过在任意两个字符 ...

  7. Manacher’s Algorithm (神啊)

    (转载自)http://blog.csdn.net/hopeztm/article/details/7932245 这里描述了一个叫Manacher’s Algorithm的算法. 算法首先将输入字符 ...

  8. Hash 算法与 Manacher 算法

    目录 前言 简单介绍 简述 Hash 冲突 离散化 基本结构 普通 Hash 简述 例题 字符串 Hash 简单介绍 核心思想 基本运算 二维字符串 Hash 例题 兔子与兔子 回文子串的最大长度 后 ...

  9. SHA1 安全哈希算法(Secure Hash Algorithm)

    安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准 (Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signatu ...

随机推荐

  1. Jmeter 05 JMeter元件详解

    1. JMeter 逻辑控制器 Switch条件控制器.While条件控制器.交替控制器.仅一次控制器.随机控制器.随机顺序控制器.条件控制器(如果(if)).循环控制器.录制控制器.ForEach控 ...

  2. poj2485

    Highways Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 27912   Accepted: 12734 Descri ...

  3. 【网络与系统安全】20179209 wireshark和nmap实验

    TCP三次握手包 在进行实验前,先梳理一遍TCP三次握手的过程,这个图是我本科学网络时画过不少于十遍的图,我觉得非常有纪念意义. 稍作解释,第一次握手,客户端发起请求连接,发送一个标志位为SYN的ip ...

  4. cocos2dx的ui封装

    cocos2dx里加载cocosudio导出的ui配置文件,在这之上封装了一下,封装核心类包括 UIManager,UILayer,UIOwner UIManager是所有ui总的管理类,代码如下: ...

  5. springboot错误页面处理

    springboot作为微服务的便捷框架,在错误页面处理上也有了一些新的处理,不同于之前的pringmvc500的页面处理是比较简单的,用java config或者xml的形式,定义如下的Bean即可 ...

  6. Django之权限用法

    **记住每一个url都是一个权限** 注册 可插拔试的权限,可以先写其他的逻辑,在最后再把权限加上 将rbac组件拷贝到项目上,注册项目 修改表结构 将写好的用户表对rbac的User表进行一对一的关 ...

  7. 我的Android进阶之旅------>介绍一款集录制与剪辑为一体的屏幕GIF 动画制作工具 GifCam

    由于上一篇文章:我的Android进阶之旅------>Android之动画之Frame Animation实例 中展示的是Frame动画效果,但是之前我是将图片截取下来,不好说明确切的动画过程 ...

  8. windows7下cmd命令窗口没有滚动条的解救方法

    由于昨天的好123问题没有解决,我想查看一下本机的ip地址等,于是打开了cmd窗口,输入ipconfig/all命令进行查看,但是发现出现了下面的窗口,无法进行滚动,完全无法查看详细的信息. 然后我百 ...

  9. 3.写一个hello world页面

    经过1和2的学习,现在已经可以正常启动Django了,这一节说怎么写一个hello world页面,所有的环境基础就是1和2中搭建的 1.在app模块中添加页面 具体为 hello_django\he ...

  10. java线程 同步临界区:thinking in java4 21.3.5

    java线程 同步临界区:thinking in java4 21.3.5 thinking in java 4免费下载:http://download.csdn.net/detail/liangru ...