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. 集合类源码(二)Collection之List(ArrayList, LinkedList, Vector)

    ArrayList 功能 完全命名 public class ArrayList<E> extends AbstractList<E> implements List<E ...

  2. 【02】Kubernets:使用 kubeadm 部署 K8S 集群

    写在前面的话 通过上一节,知道了 K8S 有 Master / Node 组成,但是具体怎么个组成法,就是这一节具体谈的内容.概念性的东西我们会尽量以实验的形式将其复现. 部署 K8S 集群 互联网常 ...

  3. 一问带你区分清楚Authentication,Authorization以及Cookie、Session、Token

    上周写了一个 适合初学者入门 Spring Security With JWT 的 Demo .Demo 地址:https://github.com/Snailclimb/spring-securit ...

  4. python基础知识(最基本)

    保留字(关键字)   False None True and as break class continue def elif else except finally for from global ...

  5. AD活动目录操作软件设计节选

    AD操作解决二级目录用户删除问题 public string DeleteADAccountOU(string commonName, string ouName) { DataTable dt = ...

  6. Cocos Creator (JavaScript手机类型判断)

    手机类型判断 var BrowserInfo = { userAgent: navigator.userAgent.toLowerCase() isAndroid: Boolean(navigator ...

  7. linq to js 用法

    /** * 排序汇总 * */ var result = Enumerable.From(vm.productList).GroupBy("$.goods_id", null, f ...

  8. Android.mk 使用说明

    Android.mk 详解https://blog.csdn.net/dearsq/article/details/50585537  Android.mk中的主要配置参数: 1.LOCAL_JACK ...

  9. C# Form 实现桌面弹幕

    使用C# Form 简单的实现了弹幕效果 0. 源代码 : https://github.com/ping9719/-desktop-barrage- 1.创建一个Form 设置  2.添加一个计时器 ...

  10. javascript之DOM(三Element类型)

    Element类型用于表现XML和HTML的元素,提供了对元素标签名.子节点及特性的访问. 要访问标签名可以使用nodeName和tagName属性,其返回值是一样的. <p id=" ...