Algorithm

Task

给定一个字符串,求其最长回文子串

Limitations

要求时空复杂度均为线性且与字符集大小无关。

Solution

考虑枚举回文串的对称轴,将其对应的最长回文子串长度 \(len\) 求出来,取最大值即为答案。

首先回文串有两种,长度为奇数的和长度为偶数的,第一种的对称轴是一个字符,第二种的对称轴在两个字符之间。

为了将两种情况统一起来,我们将原字符串的每两个相邻字符之间和首位字符前后都加上同一个不在字符集内的其他字符,例如,将 \(aaa\) 变成 \(\#a\#a\#a\#\),这样字符串的对称轴一定是一个字符了。

定义回文半径 \(r\) 为对称轴到回文串边界的字符数量,也即对称轴的下标,考虑新字符串的回文半径一定是 # 和其他字符交替出现,并以 # 结尾,因此 r 一定是奇数,而其中真正的的字符数量为 \(\frac{r - 1}{2}\),加上另一侧得字符,得到该回文串对应原字符串的回文长度为 \(\frac{r - 1}{2} \times 2~=~r - 1\)。

我们从左到右扫描新字符串,设当前扫描到了 \(i\),则 \(\forall j \in [1, ~i)\),\(len_j\) 已经被计算完毕。

设之前的所有回文子串中,右端点最大的为 \(pos\),其对应对称轴为 \(mid\)。

分两种情况讨论。

第一种情况,\(i < pos\),则 \(i\) 在以 \(pos\) 为右端点,$ mid$ 为对称轴的大回文串中。

找到 \(i\) 关于 \(mid\) 的对称点 \(j\) ,若 \(j\) 对应的回文串的左端点不在大回文串的左侧,由于回文串的对称性,对称过去以后 \(i\) 的对应回文串应该与 \(j\) 相同,于是有 \(len_i = len_j\)。

否则,在回文串内部的部分一定是对称的,对于 \(pos\) 右侧的部分,则暴力向右匹配即可。

第二种情况,\(i \geq pos\),则直接进行暴力匹配。

考虑复杂度:每次暴力匹配,\(pos\) 会自增 \(1\),而单次的复杂度是 \(O(1)\) 的,因此暴力匹配的总复杂度是 \(O(|S|)\) 的,而剩下的操作都是 \(O(1)\) 的因此总的时间复杂度是线性的。

Sample

P3805 【模板】manacher算法

Description

给定一个只由小写字母组成的回文串 \(S\),求最长回文子串长度。

Limitations

\(|S| \leq 1.1 \times 10^7\)

Solution

板板题,依然需要注意等号的位置。

在实现中,可以在字符串结尾添加另一个无关字符,这样可以保证匹配时不会越界,并且不用手动判断。

Code

#include <cstdio>
#include <algorithm> const int maxn = 22000007; int n, ans;
char S[maxn];
int len[maxn], mid[maxn]; void ReadStr(); int main() {
freopen("1.in", "r", stdin);
ReadStr();
for (int i = 1, pos = 0; i <= n; ++i) {
if (i >= pos) {
int l = pos = i;
while (S[l - 1] == S[pos + 1]) { --l; ++pos; }
len[i] = pos - i + 1;
mid[pos] = i;
} else {
int j = (mid[pos] << 1) - i;
if (len[j] < (pos - i + 1)) {
len[i] = len[j];
} else {
int l = (i << 1) - pos;
while (S[l - 1] == S[pos + 1]) { --l; ++pos; }
len[i] = pos - i + 1;
mid[pos] = i;
}
}
ans = std::max(ans, len[i]);
}
qw(ans - 1, '\n', true);
return 0;
} void ReadStr() {
static char tmp[maxn];
int _len = 0;
do tmp[++_len] = IPT::GetChar(); while ((tmp[_len] >= 'a') && (tmp[_len] <= 'z'));
tmp[_len--] = 0;
for (int i = 1; i <= _len; ++i) {
S[++n] = '#';
S[++n] = tmp[i];
}
S[++n] = '#'; S[++n] = '$';
}

【字符串】 manacher算法的更多相关文章

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

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

  2. POJ 3974 Palindrome 字符串 Manacher算法

    http://poj.org/problem?id=3974 模板题,Manacher算法主要利用了已匹配回文串的对称性,对前面已匹配的回文串进行利用,使时间复杂度从O(n^2)变为O(n). htt ...

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

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

  4. 【转载】最长回文字符串(manacher算法)

    原文转载自:http://blog.csdn.net/lsjseu/article/details/9990539 偶然看见了人家的博客发现这么一个问题,研究了一下午, 才发现其中的奥妙.Stupid ...

  5. 利用Manacher算法寻找字符串中的最长回文序列(palindrome)

    寻找字符串中的最长回文序列和所有回文序列(正向和反向一样的序列,如aba,abba等)算是挺早以前提出的算法问题了,最近再刷Leetcode算法题的时候遇到了一个(题目),所以就顺便写下. 如果用正反 ...

  6. 计算字符串的最长回文子串 :Manacher算法介绍

    转自: http://www.open-open.com/lib/view/open1419150233417.html Manacher算法 在介绍算法之前,首先介绍一下什么是回文串,所谓回文串,简 ...

  7. 算法进阶面试题01——KMP算法详解、输出含两次原子串的最短串、判断T1是否包含T2子树、Manacher算法详解、使字符串成为最短回文串

    1.KMP算法详解与应用 子序列:可以连续可以不连续. 子数组/串:要连续 暴力方法:逐个位置比对. KMP:让前面的,指导后面. 概念建设: d的最长前缀与最长后缀的匹配长度为3.(前缀不能到最后一 ...

  8. 【字符串算法2】浅谈Manacher算法

    [字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述  字符串算法2:Manacher算法 问题:给出字符串S(限制见后)求出最 ...

  9. 【字符串】manacher算法

    Definition 定义一个回文串为从字符串两侧向中心扫描时,左右指针指向得字符始终相同的字符串. 使用manacher算法可以在线性时间内求解出一个字符串的最长回文子串. Solution 考虑回 ...

  10. ACM -- 算法小结(八)字符串算法之Manacher算法

    字符串算法 -- Manacher算法 首先介绍基础入门知识,以下这部分来着一贴吧,由于是很久之前看的,最近才整理一下,发现没有保存链接,请原创楼主见谅. //首先:大家都知道什么叫回文串吧,这个算法 ...

随机推荐

  1. 024 如何让html引用公共的头部和尾部(多个html文件公用一个header.html和footer.html)

    前端静态html页面,封装公共的头文件(header:顶部页眉,顶部导航栏等部分)和尾部文件(footer:CopyRight.友情链接等部分) 当前方法:通过load()函数,引入公共头部和尾部文件 ...

  2. redis启动出现错误 can't chdir ...

    启动redis出现以下错误:[15816] *********** # Can't chdir to ’**********‘ :No such file or directory 解决方法:手动创建 ...

  3. Spring Boot2.0以上版本EmbeddedServletContainerCustomizer被WebServerFactoryCustomizer替代

    在Spring Boot2.0以上配置嵌入式Servlet容器时EmbeddedServletContainerCustomizer类不存在,经网络查询发现被WebServerFactoryCusto ...

  4. 使用 Docker 和 Jenkins 持续交付(新书免费获取!)

    今天没有长篇大论,给大家推荐一本新书,书名:Continuous Delivery with Docker and Jenkins.封面如图所示: 以下内容纯属凑字数 本书结合了 Jenkins 和 ...

  5. Window与Document

    Window 表示一个包含DOM文档的窗口,其 document 属性指向窗口中载入的 DOM文档.使用 document.defaultView 属性可以获取指定文档所在窗口.window作为全局变 ...

  6. pod的yaml例子

    apiVersion: apps/v1beta2 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selecto ...

  7. react+umi+netcore+signalR BS和客户端设备 简单通讯

    微信扫码登录工作用 仅作记录 扫码访问服务器地址 实现扫码服务器地址通讯中断设备解锁 采用signalR 双向异步通知中断 创建控制器 ChatController 注入集线器上下文 IHubCont ...

  8. Gin-Go学习笔记五:Gin-Web框架 文件的操作

    文件的操作 1>     文件的创建,删除,写入内容,读取内容.(此实例使用的是text文件) 2>     Gin 并没有提供文件的创建,删除,读写这个操作的专门的接口,所以采用的是常用 ...

  9. QPainter绘制图片填充方式(正常大小、剪切大小、自适应大小、平铺)

    Qt中QPainter提供了绘制图像的API,极大地方便了我们对图像的绘制. Qt中提供了QPixmap, QBitmap,QBitMapQImage,QPicture等图像绘图设备,它们的类关系如下 ...

  10. unity点击按钮弹出操作提示界面

    1.首先在相应的位置添加一个(UGUI控件)image,在image下添加文本框和按钮设计弹出框内容如图: 2.新建C#脚本UITips using System.Collections; using ...