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> ...
随机推荐
- CodeForce-808C Tea Party(结构体排序贪心)
Tea Party CodeForces - 808C 现在有 n 个杯子,每个杯子的容量为 a1, a2, ..., an.他现在一共有 w 毫升茶 (w ≤ a1 + a2 + ... + an) ...
- PHP的内置WEB服务器
在很多时候,我们需要简单的运行一个小 demo 来验证一些代码或者轮子是否可用,是否可以运行起来,但是去配 nginx 或者 apache 都很麻烦,其实,PHP CLI 已经提供了一个简单的测试服务 ...
- 重磅来袭!!!Elasticsearch7.14.1(ES 7.14.1)与Springboot2.5.4的整合
1. 概述 前面我们聊了 Elasticsearch(ES)集群的搭建,今天我们来聊一下,Elasticsearch(ES)集群如何与 Springboot 进行整合. Elasticsearch(E ...
- 再谈OAuth授权
工作场景流程 大家都知道OAuth是用于第三方授权的,当你用其他的APP想访问微信账号的昵称.粉丝.联系人等信息,这里就需要微信进行授权,此时在APP的网页端是可以发现有微信登录的,点开会出现弹框,在 ...
- 手把手教你 Docker搭建nacos单机版
Docker搭建nacos单机版步骤 一.使用 docker pull nacos/nacos-server 拉取nacos镜像 我这里没有指定版本所以是拉取latest,你也可以使用 docker ...
- Xftp乱码问题
Xftp出现乱码 修改编码
- python+selenium之浏览器滚动条操作
from selenium import webdriver import time #访问百度 driver=webdriver.Ie() driver.get("http://www.b ...
- YbtOJ#493-最大分数【斜率优化dp,分治】
正题 题目链接:http://www.ybtoj.com.cn/contest/117/problem/1 题目大意 \(n\)个数的一个序列,给其中的一些数打上标记. 一个标记方案的贡献为\(s_1 ...
- 10.12 LNMP
yum install nginx php php-fpm mariadb-server php-mysql php.conf server { listen 8000; # pass the PHP ...
- oracle扩展表空间
1. 查看表空间的名字及文件所在的位置 select tablespace_name, file_id, file_name, round(bytes / (1024 * 1024), 0) tot ...