【学习笔记】字符串—马拉车(Manacher)
【学习笔记】字符串—马拉车(Manacher)
一:【前言】
马拉车用于求解连续回文子串问题,效率极高。
其核心思想与 \(kmp\) 类似:继承。 ——引自 \(yyx\) 学姐
二:【算法原理】
对于任意一个回文串 \(a\),设其中点为 \(mid\)(为方便描述,偶数串则在正中央加一个位置),那么根据定义,有:
\(a[mid-1]==a[mid+1]\)
\(a[mid-2]==a[mid+2]\)
\(...\)
可知:
如果 \(a[mid-x]\) 可以形成半径为 \(r\) 的回文串,且不越过以 \(mid\) 为中心的回文串,那么 \(a[mid+x]\) 也可以形成半径为 \(r\) 的回文串。
以奇回文串为例,用 \(r[i]\) 表示以 \(i\) 为中点的最大回文串长度。
如果我们已知 \(r[mid],r[j](j \in [mid-r[mid]+1,mid-1])\),那么可以分两种情况推出其关于 \(mid\) 的对称点 \(i\) \((\frac {i+j}{2}=mid)\) 的半径:
设 \(R=mid+r[mid]-1\) 。
\((1).\) \(i+r[j]-1<=R,\) \(r[i]=r[j]\) 。
\((2).\) \(i+r[j]-1>R,\) \(r[i]=R-i+1\) 。
即 \(r[i]=min(r[j],R-i+1)\) 。
如上所述,实现了从前面信息到后面信息的继承。
继承之后还需要判断以 \(i\) 为中心能否继续扩张,这时候可以直接暴力枚举扩大半径。
三:【算法实现】
实时维护一个已知覆盖范围最靠右的回文串信息,记录其中点 \(mid\) 和右端点 \(R\)。
从 \(1,n\) 枚举 \(i\):
若 \(i<=R\) 则可以用 \(i\) 的对称点 \(mid*2-i\) 得到 \(r[i]\),
若 \(i>R\)(即 \(R=i-1\) 的情况,因为 \(R\) 永远大于等于 \(i-1\)),初始化 \(r[i]=1\),然后暴力扩大求出最大 \(r[i]\)。
如果以 \(i\) 为中点可以得到更靠右的回文串,更新 \(mid\) 和 \(R\)。
但偶数串不太好处理,所以在原字符串中的所有空隙中插入一个不可能出现的字符,例如 \('*',\) \('|'\) 等等,最前面和最后面也要插。
此时,奇数串还是奇数串,偶数串则变成了奇数串,可以统一按照奇数串处理啦。
注意:统计答案时应取真实的回文串长度。
(具体可以自己画个图分类讨论一下,会发现无论奇偶,无论是否为原字符串中的字符,\(r[i]-1\) 始终等于以 \(i\) 为中点的实际最大回文串长度。)
【Code】
题目:\(Palindrome\) \([Poj3974]\)
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<string>
#define Re register int
using namespace std;
const int N=1e6+5;
int n,R,mid,ans,OOO,r[N<<1];char op[N],a[N<<1];
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
int main(){
while(cin>>op){
if(op[0]=='E'&&op[1]=='N'&&op[2]=='D')break;//没用string就只能这样一位一位地判断了
a[0]='$',a[n=1]='*',R=0,mid=0,ans=0;
for(Re i=0;op[i];++i)a[++n]=op[i],r[n]=0,a[++n]='*',r[n]=0;//玄学填空法
for(Re i=1;i<=n;++i){
r[i]=i<=R?min(R-i+1,r[(mid<<1)-i]):1;//继承前辈的信息
while(a[i-r[i]]==a[i+r[i]])++r[i];//暴力扩张领域
if(i+r[i]-1>R)R=i+r[mid=i]-1;
ans=max(ans,r[i]-1);//取实际回文长度
}
printf("Case %d: %d\n",++OOO,ans);
}
}
四:【时间复杂度】
似乎看起来效率并不高,近似 \(O(n^2)\),但实际上它的理论复杂度是 \(O(n)\)。
为何?
对于每个 \(i\):
如果 \(i<=R\),那么直接 \(O(1)\) 计算 \(r[i]\)。
如果 \(i>R\),那么会用 \(O(len)\) 向右扫描 \(len\)个单位,所以此时 \(R\) 会向右移动 \(len+1\) 的单位。
而 \(R\) 最多只会移动 \(n\) 个单位,因此 \(Manacher\) 算法时间复杂度是线性的:\(O(n)\)。
五:【例题】
【模板】\(manacher\) 算法 \([P3805]\)
【标签】字符串/回文串/\(Manacher\) 模板\(Palindrome\) \([Poj3974]\)
【标签】字符串/回文串/\(Manacher\) 模板/\(Hash\)/二分\(Palindrome\) \(pairs\) \([CF159D]\)
【标签】字符串/回文串/\(Manacher\)/差分
【题解】\(Xing\)_\(Ling\)\(Sonya\) \(and\) \(Matrix\) \(Beauty\) \([CF1080E]\)
【标签】字符串/回文串/\(Manacher\)/暴力枚举/整体思想
【题解】\(Xing\)_\(Ling\)
【学习笔记】字符串—马拉车(Manacher)的更多相关文章
- 《python基础教程(第二版)》学习笔记 字符串(第3章)
<python基础教程(第二版)>学习笔记 字符串(第3章)所有的基本的序列操作(索引,分片,乘法,判断成员资格,求长度,求最大最小值)对字符串也适用.字符串是不可以改变的:格式化输出字符 ...
- 【Redis】命令学习笔记——字符串(String)(23个超全字典版)
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合). 本篇基于redis 4.0.11版本,学习字符串( ...
- es6学习笔记--字符串&数值&数组&函数&对象的扩展
这几天抽空学习了es6语法,关于字符串,数值,数组,函数以及对象的扩展,看到es6标准入门这本书,里面讲的扩展特别多,我认为有几部分在项目上用不到,就挑有用的当笔记学习了. 字符串的扩展 str.in ...
- Java学习笔记--字符串和文件IO
1.Java中的字符串类和字符的表示 2.区分String,StringBuilder和StringBuffer 3.从命令行中给main方法传递参数 4.文件操作 1 Java中的字符串和字符 1. ...
- Python学习笔记-字符串
Python之使用字符串 1.所有的标准序列操作(索引,分片,乘法,判断成员资格,求长度,取最小值,最大值)对字符串同样适用.但是字符串都是不可变的. 2.字符串格式化使用字符串格式化操作符即%. f ...
- Java-J2SE学习笔记-字符串转化为二维数组
1.字符串转化为二维Double数组 2.代码: package Test; public class TestDouble { public static void main(String[] ar ...
- Java学习笔记——字符串常用函数
class JavaTest4_String { public static void main(String[] args) { String str1 = "IOS,ANDROID,BB ...
- C语言学习笔记--字符串函数
字符串函数 需要包含头文件#include<stdio.h> strlen strcmp strcpy strchr strstr strcasestr
- 【学习】js学习笔记---字符串对象
一.属性 1.length 字符串的长度,且不区分中英文的字节. 示例代码: var str="abcdefghijklmn"; var str1="中文汉语" ...
- Python学习笔记 - 字符串和编码
#!/usr/bin/env python3 # -*- coding: utf-8 -*- #第一行注释是为了告诉Linux/OS X系统, #这是一个Python可执行程序,Windows系统会忽 ...
随机推荐
- Windows下硬盘存储情况可视化工具--WinDirStat
WinDirStat是一款免费的用于Windows下硬盘空间可视化工具. 下载地址:https://windirstat.en.softonic.com/ 界面如图所示: 可以轻易看出硬盘空间使用情况 ...
- Django restframework 序列化之 ModelSerializer 小记
首先介绍一下相关概念 序列化器(Serializer) 1. 自定义型: 继承rest_framework.serializers.Serializer 2. 模型类型: 继承rest_frame ...
- composer install 出现“Please provide a valid cache path”
本文背景:通过deployer部署PHP项目[deployer部署工具:https://deployer.org/] 问题:Php 的laravel框架中执行 composer install 后, ...
- Java使用MD5加密算法,实现等登陆功能
Java实现MD5加密 为了保护有些数据,就需要采取一些手段来进行数据的加密,防止被别人破解. MD5简介 md5的全称是md5信息摘要算法(英文:MD5 Message-Digest Algorit ...
- 18、Apache服务器
-- web 服务器 survey.netcraft.net --此网站会有每月份的世界上网站使用的WEB服务器的使用率统计 www.apache.org apache a ...
- 基于图的异常检测(三):GraphRAD
基于图的异常检测(三):GraphRAD 风浪 一个快乐的数据玩家/风控/图挖掘 24 人赞同了该文章 论文:<GraphRAD: A Graph-based Risky Account Det ...
- 201871010102-常龙龙《面向对象程序设计(java)》第七周学习总结
二.博文正文开头格式: 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/ ...
- 2018710101110-李华《面向对象程序设计(java)》第十二周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- 283.移动零 关于列表list与remove原理*****(简单)
题目: 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 注意,该题目要求不开辟行的数组空间,在原数据上进行操作. 示例: 输入: [0,1,0,3,12 ...
- VIJOS-P1201 高低位交换
洛谷 P1100 高低位交换 https://www.luogu.org/problemnew/show/P1100 JDOJ 1349: VIJOS-P1201 高低位交换 https://neoo ...