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. EasyNVR、EasyDSS二次开发之:RTMP、HLS流在web页面进行无插件播放示例Demo代码

    不管是基于EasyNVR还是EasyDSS,都是支持无插件直播,这也是未来视频直播的一个趋势.对于传统的浏览器插件播放谁用谁知道: 以上是软件自带播放展示 背景需求 对于EasyNVR和EasyDSS ...

  2. 解决 ie 返回json提示下载 ResponseEntity方法

    js 配合java  springMVC后台,成功后返回消息,chrom ff都正常,只有IE提交后返回的JSON提示下载,查看类型 application/json  google后发现原来是IE不 ...

  3. DNN自适应

  4. SNMP 监控方式的配置

    由于某些设备并不能安装 Agent,或者不方便安装 Agent 等因素,将采用 SNMP 方式进行监控 1.Linux 配置 SNMP [root@crazy-acong ~]# yum -y ins ...

  5. Bootstrap导航栏头部错位问题

    代码: <section class="header"> <div class="container"> <div class=& ...

  6. Bootstrap学习-菜单-按钮-导航

    1.下拉菜单(基本用法) 在使用Bootstrap框架的下拉菜单时,必须调用Bootstrap框架提供的bootstrap.js文件.当然,如果你使用的是未编译版本,在js文件夹下你能找到一个名为“d ...

  7. [luogu4315]月下“毛景树”

    [luogu4315]月下"毛景树" luogu 联赛前复习一发树剖.不会告诉你WA了4发 #define ls x<<1,l,mid #define rs x< ...

  8. Bootstrap 轮播图(Carousel)插件

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. header函数使用

    header('HTTP/1.1 200 OK'); //设置一个404头: header('HTTP/1.1 404 Not Found'); //设置地址被永久的重定向 header('HTTP/ ...

  10. [转载]设计模式的UML图

    1.抽象工厂(Abstract Factory)模式 意图:为特定的客户(或情况)提供特定系列的对象. 2.类的适配器(Adapter)模式 意图:将一个类的接口转换成客户希望的另外一个接口. 3.对 ...