Manacher算法 求 最长回文子串
1 概述(扯淡)
在了解Manacher算法之前,我们得先知道什么是回文串和子串。
回文串,就是正着看反着看都一样的字符串。比如说“abba”就是一个回文串,“abbc”则不是一个回文串。
一个字符串的子串,就是原字符串中连续的一段字符。比如说“abc”就是“abcdefg”的子串,“ace”和“bsp”则不是“abcdefg”的子串。
那么,一个字符串的最长回文子串就是这个字符串所有为回文串的子串中最长的一个子串。Manacher(马拉车)这个算法要求解的,就是一个字符串中的最长回文子串。
2 算法流程
2.0 准备工作
回文串可以分为两种,一种是长度为奇数的回文串,比如说“cac”;一种是长度为偶数的回文串,比如说“acca”。
这样的话,我们就要分开来处理,好麻烦的咯。其实,我们可以在每两个字符的中间以及开头和结尾插入一个特殊字符,比如说“#”。这样的话,所有的回文串的长度就都变成奇数的了。
举个例子,有一个字符串“aabbabba”,将其进行上述处理后,就变成了这样:“#a#a#b#b#a#b#b#a#”。为了减少边界的处理,我们还可以再在首尾插入两个特殊字符,这两个特殊字符必须和之前插入的特殊字符不相同,并且这两个字符之间也不能相同,比如说“$”和“@”。于是,“#a#a#b#b#a#b#b#a#”就变成了“$#a#a#b#b#a#b#b#a#@”。
值得注意的是,当按照上述方法对字符串进行处理时,不要忘了数组要开到字符串长度的两倍。
(我不会告诉你我Mancher模板因为数组开小RE爆了一次零)
至此,我们的准备工作就做完了。
2.1 正式处理
先给出几个说明:
p:当前已知的所有回文串中,右端点最靠右的回文串的中心。
maxp:当前已知的所有回文串中,右端点最靠右的回文串的右端点
位置i的回文半径:设以位置i为中心的所有回文串中,最长的回文串所对应的区间[l,r],则位置i的回文半径为区间[i,r]的长度。比如说在字符串“wabbba”中,位置4的回文半径即为3。
r[i]:位置i的回文半径。
我们现在的任务就是对于每一个位置i,都求出其r[i]。这样,我们就可通过r[i]来直接算出最长回文子串的长度了。
假如我们当前已经处理到了字符串的第i个位置,则有以下几种情况:
1.i>maxp
当出现这种情况时,直接暴力扩展求出r[i]。
2.i≤maxp
这时,我们设j为i关于p的对称点,则j=p-(i-p)。
2.1.maxp-i+1>r[j]
这时,我们直接令r[i]=r[j]即可。因为i和j此时都处于一个回文串内,且分别在这个回文串的中心p的两侧,r[i]也并没有延伸到这个回文串的边界或边界以外,所以两边的情况是相同的,直接赋值即可。
图示:

2.2.maxp-i+1≤r[j]
这时,我们先令r[i]=maxp-i+1,然后再暴力扩展更新r[i]即可。为什么这时不能直接将r[j]的值赋给r[i]呢?这是因为,r[j]已经延伸到了以p为中心的回文串的边界或边界之外,回文串两侧外的情况是不同的,所以不能像上一种情况那样直接赋值。
图示:

最后,我们维护一下p,maxp和答案就好。
3 时间复杂度
不难看出,Mancher算法的时间复杂度为O(n),其中n为字符串的长度。这是因为每个r[i]暴力扩展次数的总和是不会超过n次的(想想为什么)。
4 代码实现
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int r[22000005];
char st[22000005];
int main()
{
int k=0;
char ch=' ';
while(ch<'a'||ch>'z') ch=getchar(); //---|
st[0]='$',st[++k]='#'; // |-读入字符串
while(ch>='a'&&ch<='z') st[++k]=ch,st[++k]='#',ch=getchar(); // |-并插入特殊字符
st[k+1]='@'; //---|
int p=0,ans=0,maxp=0;
for(int i=1;i<=k;i++)
{
if(i>maxp) //------|
while(st[i-r[i]]==st[i+r[i]]) r[i]++; // |
else // |-分
{ // |-情
int j=p-(i-p); // |-况
if(maxp-i+1>r[j]) r[i]=r[j]; // |-处
if(maxp-i+1<=r[j]) // |-理
{ // |
r[i]=maxp-i+1; // |
while(st[i-r[i]]==st[i+r[i]]) r[i]++; // |
} // |
} //------|
if(i+r[i]-1>maxp) maxp=i+r[i]-1,p=i;//维护maxp和p
ans=max(ans,(r[i]+r[i]-1)>>1);//更新答案
}
printf("%d",ans);
return 0;
}
5 练习题
Manacher算法 求 最长回文子串的更多相关文章
- Manacher算法——求最长回文子串
首先,得先了解什么是回文串.回文串就是正反读起来就是一样的,如“abcdcba”.我们要是直接采用暴力方法来查找最长回文子串,时间复杂度为O(n^3),好一点的方法是枚举每一个字符,比较较它左右距离相 ...
- manacher算法求最长回文子串
一:背景 给定一个字符串,求出其最长回文子串.例如: s="abcd",最长回文长度为 1: s="ababa",最长回文长度为 5: s="abcc ...
- Manacher算法 - 求最长回文串的利器
求最长回文串的利器 - Manacher算法 Manacher主要是用来求某个字符串的最长回文子串. 不要被manacher这个名字吓倒了,其实manacher算法很简单,也很容易理解,程序短,时间复 ...
- manacher算法求最长回文子序列
一:背景 给定一个字符串,求出其最长回文子串.例如: s="abcd",最长回文长度为 1: s="ababa",最长回文长度为 5: s="abcc ...
- 使用manacher算法解决最长回文子串问题
要解决的问题 求一个字符串最长回文子串是什么.且时间复杂度 O(N) 具体描述可参考: LeetCode_5_最长回文子串 LintCode_200_最长回文子串 暴力解法 以每个字符为中心向左右两边 ...
- hdu 3068 最长回文 (Manacher算法求最长回文串)
参考博客:Manacher算法--O(n)回文子串算法 - xuanflyer - 博客频道 - CSDN.NET 从队友那里听来的一个算法,O(N)求得每个中心延伸的回文长度.这个算法好像比较偏门, ...
- 小白月赛13 B小A的回文串 (马拉车算法求最长回文子串)
链接:https://ac.nowcoder.com/acm/contest/549/B来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言52428 ...
- leetcode 5 Longest Palindromic Substring(Manacher算法求最长回文串)
应用一下manacher算法就可以O(n)求出结果了.可以参考hdu3068 substr(start,length)函数是这样用的: substr 方法 返回一个从指定位置开始,并具有指定长度的子字 ...
- Manacher算法求最长回文串模板
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> ...
随机推荐
- composer 包 slim使用案例,一个简单的路由解决方案
nginx配置文件修改 location / { try_files $uri /index.php$is_args$args; } 设置好nginx伪静态,把所有的请求方式都转向到index.php ...
- STM32F103C8T6使用SPI接口驱动WS2812b灯条
之前一篇文章写了使用IO控制WS2812b操作原理,但是由于IO的输出比较慢,所以现在改用了硬件SPI控制WS2812b灯条 把SPI的mosi线接到ws2812b的数据线,SPI的速率可达十几Mbi ...
- 无序数组求第K大的数
问题描述 无序数组求第K大的数,其中K从1开始算. 例如:[0,3,1,8,5,2]这个数组,第2大的数是5 OJ可参考:LeetCode_0215_KthLargestElementInAnArra ...
- ecshop刷新页面出现power by ecshop和链接的解决办法
当小伙伴在使用echop模板进行修改的时候,如果你删掉底部自带版权后,再调试程序刷新界面的时候,时不时就会冒出一个power by ecshop,而且是带有链接的,很不舒服,所以需要去掉,下面是最简单 ...
- python mysql增加改查
#python mysql增加改查,方便日后copy/paste .......... 1 #encoding: UTF-8 2 import pymysql 3 # # 打开数据库连接 4 db = ...
- 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念 | 百篇博客分析OpenHarmony源码 | v25.01
百篇博客系列篇.本篇为: v25.xx 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...
- P4716-[模板]最小树形图
正题 题目链接:https://www.luogu.com.cn/problem/P4716 题目大意 给出\(n\)个点\(m\)条边的一张有向图,求以\(r\)为根的最小外向树. \(1\leq ...
- 今天我抓了个 HTTPS 的包
之前写过一篇讲 HTTPS 的思想的文章. 破玩意 | 用 HTTPS 传纸条 后来又写了篇用更凝练的语言总体描述了 HTTPS 的主干. 叮咚 | HTTPS 的分支和主干 想必通过这两篇文章,HT ...
- 当一个 Pod 被调度时,Kubernetes 内部发生了什么?
在 Kubernetes 中,调度是指将 Pod 放置到合适的 Node 上,然后对应 Node 上的 Kubelet 才能够运行这些 Pod . kube-scheduler 是集群控制平面的主要组 ...
- NOIP&CSP 考前 Dev-cpp 的选项问题和考试心态
(进入考场后您将获得一个崭新的 \(Dev-cpp\),没有中文,没有编译选项,没有缺省源:我还将获得一个崭新的脑子,没有心态,没有智商,没有调试能力--) 中文 \[Step1 \] \[Step2 ...