【字符串】 manacher算法
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算法的更多相关文章
- 第5题 查找字符串中的最长回文字符串---Manacher算法
转载:https://www.felix021.com/blog/read.php?2040 首先用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一 ...
- POJ 3974 Palindrome 字符串 Manacher算法
http://poj.org/problem?id=3974 模板题,Manacher算法主要利用了已匹配回文串的对称性,对前面已匹配的回文串进行利用,使时间复杂度从O(n^2)变为O(n). htt ...
- 最长回文字符串(manacher算法)
偶然看见了人家的博客发现这么一个问题,研究了一下午, 才发现其中的奥妙.Stupid. 题目描述: 回文串就是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串. ...
- 【转载】最长回文字符串(manacher算法)
原文转载自:http://blog.csdn.net/lsjseu/article/details/9990539 偶然看见了人家的博客发现这么一个问题,研究了一下午, 才发现其中的奥妙.Stupid ...
- 利用Manacher算法寻找字符串中的最长回文序列(palindrome)
寻找字符串中的最长回文序列和所有回文序列(正向和反向一样的序列,如aba,abba等)算是挺早以前提出的算法问题了,最近再刷Leetcode算法题的时候遇到了一个(题目),所以就顺便写下. 如果用正反 ...
- 计算字符串的最长回文子串 :Manacher算法介绍
转自: http://www.open-open.com/lib/view/open1419150233417.html Manacher算法 在介绍算法之前,首先介绍一下什么是回文串,所谓回文串,简 ...
- 算法进阶面试题01——KMP算法详解、输出含两次原子串的最短串、判断T1是否包含T2子树、Manacher算法详解、使字符串成为最短回文串
1.KMP算法详解与应用 子序列:可以连续可以不连续. 子数组/串:要连续 暴力方法:逐个位置比对. KMP:让前面的,指导后面. 概念建设: d的最长前缀与最长后缀的匹配长度为3.(前缀不能到最后一 ...
- 【字符串算法2】浅谈Manacher算法
[字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述 字符串算法2:Manacher算法 问题:给出字符串S(限制见后)求出最 ...
- 【字符串】manacher算法
Definition 定义一个回文串为从字符串两侧向中心扫描时,左右指针指向得字符始终相同的字符串. 使用manacher算法可以在线性时间内求解出一个字符串的最长回文子串. Solution 考虑回 ...
- ACM -- 算法小结(八)字符串算法之Manacher算法
字符串算法 -- Manacher算法 首先介绍基础入门知识,以下这部分来着一贴吧,由于是很久之前看的,最近才整理一下,发现没有保存链接,请原创楼主见谅. //首先:大家都知道什么叫回文串吧,这个算法 ...
随机推荐
- 企业微信同步LDAP
1.需求 定期同步企业微信的用户信息到 LDAP 中,当有新用户时,会自动发送LDAP的账号密码给该用户邮箱. 2.环境 python 3.x 需要安装两个模块 pip install ldap3 r ...
- python解决自动化测试静态页面加载慢的情况
# coding:utf8from selenium import webdriverimport time # 创建一个ChromeOptions的对象option = webdriver.Chro ...
- SQL ----------- 借助视图写多表查询
在多表查询中可能遇到两表.三表乃致四表查询,自己进行直接用sql 语句进行书写的话可能比较难,但是可以借助视图进行分析,书写 1.右击视图点击新建 选择需要的表点击添加,注意两个表之间要有相同的字段 ...
- Jenkins集成Sonar Quabe和权限配置
目录 安装Sonar Jenkins配置sonar Maven Jenkins Job配置 Pipeline Jenkins Job配置 Sonar权限管理 Sonar quality Gate通过阈 ...
- 第二十节:Asp.Net Core WebApi生成在线文档
一. 基本概念 1.背景 使用 Web API 时,了解其各种方法对开发人员来说可能是一项挑战. Swagger 也称为OpenAPI,解决了为 Web API 生成有用文档和帮助页的问题. 它具有诸 ...
- java poi 读取有密码加密的Excel文件
String excelPath = "Excel文件路徑"; String password = "Excel文件密碼"; Workbook workbook ...
- Pandas操作excel
读取excel:Pandas库read_excel()参数详解 pandas.read_excel(io,sheet_name = 0,header = 0,names = None,index_co ...
- .net core SIMD范例分析
单指令多数据流(SIMD)是CPU基本运算之外为了提高并行处理多条数据效率的技术,常用于多媒体处理如视频,3D模拟的计算.实现方式不同品牌的CPU各有自己的指令集,如SSE MMX 3DNOW等. C ...
- dotnet core 之 gRPC
dotnet core gRPC 原文在本人公众号中,欢迎关注我,时不时的会分享一些心得 HTTP和RPC是现代微服务架构中很常用的数据传输方式,两者有很多相似之处,但是又有很大的不同.HTTP是一种 ...
- python 函数式编程 闭包,返回一个函数
参考链接:https://www.liaoxuefeng.com/wiki/1016959663602400/1017434209254976 作业 #使用生成器 def createCounter( ...