Manacher算法可以在\(O(N)\)时间内求解出一个字符串的所有回文子串(正反遍历相同的字串)

注:回文串显然有两种,一种是奇数长度,如abczcba,有一个中心字符z;另外一种是偶数个长度,如abccba,没有中心字符,下面提到暂时都是只查找奇数长度的字符串

要理解Manacher算法,首先假象一个随机生成的字符串,枚举每个字符作为中心,向两边不断拓展,判断是否相等,直到两边不相等或者走到边界为止,就可以得到每个字符为中心的最大回文长度了(记作\(f_i\)),显然第\(i\)个字符加上左右\(f_i\)的字符就可以构成\(i\)为中心的最长回文串\(S_{[i-f_i+1, i+f_i-1]}\),而\(i\)为中心的更短的字串,显然也是回文串了,这样就求出了所有回文串。

void BF(char *s, int len, int *f) {
for (int i = 1; i <= len; i++) {
f[i] = 1;
while (s[i+f[i]] == s[i-f[i]]) ++f[i];
}
}

但是如果字符大量重叠(如abababab...),几乎每次拓展都会拓展到最边界,效率就会达到平方级。解决这个问题,就应该想到利用回文串的性质,利用已经得到的\(f_i\)来推出当前的\(f_i\)。

那么回文串有什么性质?首先是对称下标构成的字串肯定对称(比如abczcba,\(S_{[1, 3]}=S_{[7, 4]}\)),而且回文串的对称串依然是自己(定义)。所以,一个回文串中如果有另一个回文串,那么子串的对称下标肯定也构成了一个相同的回文串,可以直接推出来。换言之,如果我们知道一个回文串内左半边的对称串,就可以直接得到他右半边的对称串

所以我们记录下达到过的最靠右的点和他的中心点(记为\(maxR\)和\(mid\),当然你也可以只记录\(mid\),用\(mid+f[mid]\)表示右边界)。只要枚举的\(i\)还在右边界以内,就尝试用\(f[mid*2-i]\)来更新\(f[i]\)。当然如果左半边回文串的最长左边界\(i-f[i]+1\)已经不在\(mid\)的回文范围内了,那就顶到最左边,把\(f[i]\)更新为\(f[mid]+mid-i\)(也就是最右边\(maxR\)处)。这时就需要继续往后更新,将\(maxR\)往右拓展。

这里是一份参考代码,这里\(maxR\)是开区间。和上面的暴力一样没有做边界特判,应该将\(S[0]和S[len+1]\)设为两个原字符串中没有且不相等的字符(否则可能加上两端,多一个回文串,然后再往外走导致越界)。显然\(f[i]\)取\(f[mid]+mid-i\)时才会执行之后的更新。

void Manacher(char *s, int len, int *f) {
static int maxR, mid;
for (int i = 1; i <= len; i++) {
f[i] = (i < maxR) ? min(f[mid*2-i], f[mid]+mid-i) : 1;
while (s[i+f[i]] == s[i-f[i]]) ++f[i];
if (i + f[i] > maxR)
maxR = (mid = i) + f[i];
}
}

那么为什么只需要这一个优化就可以做到线性呢?因为这样已经可以做到每个字符只被访问一次(算上和后面的字符比较相等就是两次)。回看第一张图,\(maxR\)左侧是已经访问过的,右侧是没有访问过的。这些已经访问过但\(i\)还没有遍历到的位置都可以\(O(1)\)求解,而\(maxR\)只会不断向右移动,因此一定是\(O(N)\)的。其本质就是利用回文串的性质避免了\(mid\)到\(maxR\)处的所有计算,只在往后更新的时候计算。

最后谈谈偶数长度回文串,偶数长度串的“中心”相当于于是字符之间的空隙。处理它们的一种方法是在每两个字符串之间加入不存在于原字符串的字符(如#),然后在执行算法,此时以#为中心的回文串就是偶数回文串。或者先做奇数长度,然后找到所有满足\(S[i]==S[i+1]\)的下标,将他们看作“一个中心“后进行拓展。

for (int i = 1; i <= len; i++)
s0[(i << 1) - 1] = s[i], s0[i << 1] = '#';

Manacher算法求解回文字符串的更多相关文章

  1. Codeforces Global Round 7 D2. Prefix-Suffix Palindrome (Hard version)(Manacher算法+输出回文字符串)

    This is the hard version of the problem. The difference is the constraint on the sum of lengths of s ...

  2. SPOJ STC02 - Antisymmetry(Manacher算法求回文串数)

    http://www.spoj.com/problems/STC02/en/ 题意:给出一个长度为n的字符串,问其中有多少个子串s可以使得s = s按位取反+翻转. 例如样例:11001011. 10 ...

  3. hdu5340—Three Palindromes—(Manacher算法)——回文子串

    Three Palindromes Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others ...

  4. HDU 5371(2015多校7)-Hotaru&#39;s problem(Manacher算法求回文串)

    题目地址:HDU 5371 题意:给你一个具有n个元素的整数序列,问你是否存在这样一个子序列.该子序列分为三部分,第一部分与第三部分同样,第一部分与第二部分对称.假设存在求最长的符合这样的条件的序列. ...

  5. Manacher算法求回文半径

    http://wenku.baidu.com/link?url=WFI8QEEfzxng9jGCmWHoKn0JBuHNfhZ-tKTDMux34CeY8UNUwLVPeY5HA3TyoKU2XegX ...

  6. Manacher算法:求解最长回文字符串,时间复杂度为O(N)

    原文转载自:http://blog.csdn.net/yzl_rex/article/details/7908259 回文串定义:"回文串"是一个正读和反读都一样的字符串,比如&q ...

  7. 最长回文字符串(manacher算法)

    偶然看见了人家的博客发现这么一个问题,研究了一下午, 才发现其中的奥妙.Stupid. 题目描述:      回文串就是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串. ...

  8. 第5题 查找字符串中的最长回文字符串---Manacher算法

    转载:https://www.felix021.com/blog/read.php?2040 首先用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一 ...

  9. hdu3068 求一个字符串中最长回文字符串的长度 Manacher算法

    最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

随机推荐

  1. CSS 常用颜色代号

    常用颜色代号一览表:http://www.divcss5.com/html/h636.shtml   #000000   #2F0000   #600030   #460046   #28004D   ...

  2. PowerShell配置文件后门

      PowerShell 配置文件是在 PowerShell 启动时运行的脚本.   在某些情况下,攻击者可以通过滥用PowerShell配置文件来获得持久性和提升特权.修改这些配置文件,以包括任意命 ...

  3. 【九度OJ】题目1435:迷瘴 解题报告

    [九度OJ]题目1435:迷瘴 解题报告 标签(空格分隔): 九度OJ http://ac.jobdu.com/problem.php?pid=1435 题目描述: 通过悬崖的yifenfei,又面临 ...

  4. css--深入理解z-index引发的层叠上下文、层叠等级和层叠顺序

    前言 在编写css样式代码的时候,我们经常会遇到z-index属性的使用,我们可能只了解z-index能够提高元素的层级,并不知道具体是怎么实现的.本文就来总结一个由z-index 引发的层叠上下文和 ...

  5. Chapter 3 Observational Studies

    目录 概 3.1 3.2 Exchangeability 3.3 Positivity 3.4 Consistency First Second Fine Point 3.1 Identifiabil ...

  6. CS5216 设计于DP转HDMI转换器|DP转HDMI 1080P中继器 电平转化器开关设计方案与线路图

    CS5216是一款Displayport to hdmi 1080p音视频信号转换芯片,主要用于设计与开发DP转HDMI 转换器.中继器.电平转换器等产品当中.它支持交流和直流耦合TMDS信号高达1. ...

  7. Java实习生常规技术面试题每日十题Java基础(七)

    目录 1. Java设计模式有哪些? 2.GC是什么?为什么要有GC? 3. Java中是如何支持正则表达式. 4.比较一下Java和JavaSciprt. 5.Math.round(11.5) 等于 ...

  8. Java实习生常规技术面试题每日十题Java基础(三)

    目录 1.是否可以从一个static方法内部发出对非static方法的调用? 2.Integer与int的区别? 3.Overload和Override的区别.参数列表相同,返回值不同的方法,是否是重 ...

  9. 【入门到精通】❤️「Java工程师全栈知识路线」

    持续更新中- Vue前端开发 章节 内容 实践练习 Vue.js高效前端开发 • (实践练习) 第1章 Vue.js高效前端开发 • [ 一.初识Vue.js ] 第2章 Vue.js高效前端开发 • ...

  10. 编写Java程序,使用PreparedState实现对英雄数据的新增、删除和更新

    返回本章节 返回作业目录 需求说明: 使用PreparedState实现对英雄数据的新增.删除和更新 英雄(t_hero)表结构 列名(含义) 数据类型 约束 id (序号) int 主键,自动增长 ...