浅谈Manacher算法
Manacher
manacher是一种\(O(n)\)求最长回文子串的算法,俗称马拉车(滑稽)
直接步入正题
首先可以知道的是:每一个回文串都有自己的对称中心,相应的也有自己的最大延伸长度(可以称之为“半径”)
我们设\(rad[i]\)表示以\(i\)为中心的回文子串的半径,那么只需要知道所有的\(rad[i]\)就可以求出最长回文子串了
从\(1\)到\(n\)枚举\(i\),求解\(rad[i]\)
设当前已经求到了\(rad[k]\),设前\(k-1\)个数中\(rad[i]+i\)(即右端点)最大的数为\(mid\),令\(r=mid+rad[mid]\)
那么可以证明一个点\(i\)关于\(mid\)的对称点是\(2\times mid-i\)(两点距离公式)
opt1:如果\(k\leq r\)
方便起见,令\(j=2\times mid-k\)
1.若\(j-rad[j]>mid-rad[mid]\),即以\(j\)点为中心的最长回文子串的左端点在以\(mid\)为中心的最长回文子串的左端点右边,则\(rad[i]\)可以直接由\(rad[j]\)转移过来(因为\(2\times mid-r\)$mid$和$mid$\(r\)是对称的,所以\(k\)的半径和\(j\)的半径是一样的),即\(rad[i]=rad[j]\)
2.若\(j-rad[j]\leq mid-rad[mid]\),则\(rad[k]\)至少是\(r-k\)。接下来再暴力延伸,顺便更新\(mid\)和\(r\)
opt2:如果\(k>r\)
直接暴力延伸,顺便更新\(mid\)和\(r\)
可以发现每次暴力延伸的时候,暴力延伸多少,\(r\)也会变化多少,且\(r\)是递增的且不超过\(n\)的数
关于复杂度:
由于每一个字符最多只会被遍历一次,所以复杂度是\(O(n)\)的
实现细节:
1.由于长度为偶数的回文串对称中心并不能实际找到,所以在两个字符之间插入#。这样不会影响答案,并且可以解决这个问题
2.对于不同情况的相似之处可以合并到一起来降低码量,如op1.1的直接转移和opt1.2的转移等
3.不要忘了更新\(mid\)和\(r\)
4.注意下标
代码:
#include<bits/stdc++.h>
using namespace std;
char cString[22000005];
int iRad[22000005];
int iLen,iAns;
void read()
{
char c = getchar();
cString[0] = '|', cString[++iLen] = '#';
while(c < 'a' || c > 'z') c = getchar();
while(c >= 'a'&& c <= 'z') cString[++iLen] = c, cString[++iLen] = '#', c = getchar();
}
int main()
{
read();//读入
for(int i = 1, mid = 0, r = 0; i <= iLen; i++)
{
if(i <= r) iRad[i] = min(iRad[mid * 2 - i], r - i + 1);//opt1
while(cString[i - iRad[i]] == cString[i + iRad[i]]) ++iRad[i];//opt1.2,opt2 尝试暴力延伸
if(i + iRad[i] > r) r = i + iRad[i] - 1, mid = i;//更新mid和r
if(iRad[i] > iAns) iAns = iRad[i];//更新答案
}
printf("%d", iAns-1);
}
浅谈Manacher算法的更多相关文章
- 浅谈Manacher算法与扩展KMP之间的联系
首先,在谈到Manacher算法之前,我们先来看一个小问题:给定一个字符串S,求该字符串的最长回文子串的长度.对于该问题的求解.网上解法颇多.时间复杂度也不尽同样,这里列述几种常见的解法. 解法一 ...
- 【字符串算法2】浅谈Manacher算法
[字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述 字符串算法2:Manacher算法 问题:给出字符串S(限制见后)求出最 ...
- 浅谈分词算法(5)基于字的分词方法(bi-LSTM)
目录 前言 目录 循环神经网络 基于LSTM的分词 Embedding 数据预处理 模型 如何添加用户词典 前言 很早便规划的浅谈分词算法,总共分为了五个部分,想聊聊自己在各种场景中使用到的分词方法做 ...
- 浅谈分词算法(4)基于字的分词方法(CRF)
目录 前言 目录 条件随机场(conditional random field CRF) 核心点 线性链条件随机场 简化形式 CRF分词 CRF VS HMM 代码实现 训练代码 实验结果 参考文献 ...
- 浅谈分词算法(3)基于字的分词方法(HMM)
目录 前言 目录 隐马尔可夫模型(Hidden Markov Model,HMM) HMM分词 两个假设 Viterbi算法 代码实现 实现效果 完整代码 参考文献 前言 在浅谈分词算法(1)分词中的 ...
- 浅谈分词算法基于字的分词方法(HMM)
前言 在浅谈分词算法(1)分词中的基本问题我们讨论过基于词典的分词和基于字的分词两大类,在浅谈分词算法(2)基于词典的分词方法文中我们利用n-gram实现了基于词典的分词方法.在(1)中,我们也讨论了 ...
- 【字符串算法3】浅谈KMP算法
[字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述 [字符串算法3]KMP算法 Part1 理解KMP的精髓和思想 其实KM ...
- 浅谈Manacher
\(Manacher\)是由一个叫做\(Manacher\)的人发明的能在\(O(n)\)时间内找出一个字符串长度最长的回文子串的算法. 由于偶回文串形如\(abba\)这样的不好找对称中心,所以我们 ...
- 浅谈Tarjan算法
从这里开始 预备知识 两个数组 Tarjan 算法的应用 求割点和割边 求点-双连通分量 求边-双连通分量 求强连通分量 预备知识 设无向图$G_{0} = (V_{0}, E_{0})$,其中$V_ ...
随机推荐
- elastic 查询
1.match 查询 GET /_index/_search { "query": { "match": { " } } } 1.match 多条件查 ...
- Linux fing cd 查找文件/文件夹并进入目录命令
查找文件|文件夹并进入目录命令:cd $() [root@localhost /]# cd $(dirname "`find / -name 'ifcfg-ens33'`") // ...
- redis如何查看主从状态信息master和salve
首先你需要连接上redis [root@localhost src]# ./redis-cli -p 6384 --第一步从客户端命令工具连接redis 127.0.0.1:6384> auth ...
- 《编译原理》求 FIRSTVT 集和 LASTVT 集的步骤 - 例题解析
<编译原理>求 FIRSTVT 集和 LASTVT 集的步骤 - 例题解析 算符优先关系表的构造中涉及到求 FIRSTVT 集和 LASTVT 集. 表示及含义: FIRSTVT(T) 非 ...
- Mongodb的锁 原子性 隔离性 一致性
读写锁 Mongodb使用读写锁来来控制并发操作: 当进行读操作的时候会加读锁,这个时候其他读操作可以也获得读锁.但是不能或者写锁. 当进行写操作的时候会加写锁,这个时候不能进行其他的读操作和写操作. ...
- Android编程使用httpHelper不执行错误-20171017
解决方法:将显示等代码(例如setText()和setAdapter()等方法)从主函数onCreate()中移到httpHelper.get()函数中: 原因:有可能是主线程运行的较快,而连接服 ...
- 常用ASCII码表
- Apache工作流程
一个经典的Apache处理php页面的流程 需要连接mysql数据库并处理的流程 网站是一系列网页的组合 从用户角度看就是访问诸如 hhtp://www.baidu.com -----url 这是互联 ...
- k8s-insight测试
eureka apiVersion: v1 kind: Pod metadata: name: eureka labels: ccb: eureka spec: containers: - name: ...
- yum 安装 mongodb
1 .添加阿里源 vi /etc/yum.repos.d/mongodb.repo [mongodb-org] name=MongoDB Repository baseurl=http://mirro ...