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. Linux 服务器上建立用户并分配权限

    查看用户 whoami #要查看当前登录用户的用户名 who am i #表示打开当前伪终端的用户的用户名 who mom likes who 命令其它常用参数 参数 说明 -a 打印能打印的全部 - ...

  2. 【BZOJ4375】Selling Tickets 随机化

    [BZOJ4375]Selling Tickets Description 厨师在一次晚宴上准备了n道丰盛的菜肴,来自世界各地的m位顾客想要购买宴会的门票.每一位顾客都有两道特别喜爱的菜,而只要吃到了 ...

  3. 如何使用EasyNVR+CDN突破萤石云在直播客户端数量上的限制,做到低成本高性价比的直播

    恰逢五一假期,有以为来自内蒙的用户向我电话咨询,大概的场景是这样的: 目前用户使用的是全套的海康IPC和NVR设备: 海康NVR设备通过设置萤石云平台,由萤石云对外提供直播服务: 萤石云对单个摄像机同 ...

  4. Ax=λx=λIx

  5. saltStack 证书管理

    SaltStack 使用 SSL 签证的方式进行安全认证,我们可以在 Master 端看到 Minion 端的整数签证请求 1.查看当前证书签证情况 [root@SaltStack-Master ~] ...

  6. Java编程中的一些常见问题汇总

    转载自  http://macrochen.iteye.com/blog/1393502 每天在写Java程序,其实里面有一些细节大家可能没怎么注意,这不,有人总结了一个我们编程中常见的问题.虽然一般 ...

  7. WiX 中XML引用变量说明

    WiX 安装工程中的XML 文件所引用变量说明: The WiX project supports the following project reference variables: Variabl ...

  8. Django之stark组件2

    action批量处理功能 用户可以自定义批量处理功能,但是默认的有批量删除功能. ***思路*** 1,定义一个列表用来装action的类名并extend用户自定义列表 2.循环该列表获取到函数名(用 ...

  9. 分析DNS解析时间

    提高网页的打开速度,一般地我们会选择使用CDN,利用“就近原则”让用户在最短的时间内获取到服务器资源,实际应用当中采用CDN的方式提高网站访问速度的效果也是最明显的.这也就是为什么国外的空间打开速度远 ...

  10. 如何解决Asp.Net MVC和WebAPI的Controller名称不能相同的问题

    1.问题描述 假如有一个文章的业务(Article),我们在 Controllers文件夹中创建MVC Controller和Api Controller,各个Controller中都有相同的获取文章 ...