【字符串题目讲解】一文理解 Manacher Algoirth(马拉车算法)——以洛谷 P3805 和 P5446 为例

M a n a c h e r A l g o r i t h m \mathrm{Manacher\ Algorithm} Manacher Algorithm

Manacher 算法主要是解决怎样的问题呢,其实是求解最长的回文串,但是只能找到长度为奇数的回文串,不过可以通过转化使得能够求解任意长度的回文串。

例题:P3805 【模板】manacher

A l g o r i t h m F l o w \mathrm{Algorithm\ Flow} Algorithm Flow

Manacher 的算法是在 O ( n ) O(n) O(n) 的时间复杂度内,查找对于每一个 i i i,最大的回文半径 p i p_i pi 是多少?

从左往右递推做,在递推的过程中,每一次维护右端点最靠右的回文串的中心位置 m i d mid mid,以及该回文串最靠右的位置 m r mr mr(通常不包含该回文串最靠右的位置,即为该位置 + 1 +1 +1)。(如图)

那么,对于求解 i i i p i p_i pi,可以分情况讨论:

  • i i i m r mr mr 的左边,即在 m i d mid mid 所在回文串的内部。那么,充分利用已经算过的信息,考虑 i i i 在该回文串内的对应点 j j j,其中 j = m i d × 2 − i j=mid\times 2 - i j=mid×2i
  • j j j 所在的最大回文串仍然在 m i d mid mid 所在回文串的范围内,则 p i ≥ p j p_i\ge p_j pipj。(何时取 ≥ \ge ,当且仅当 j j j 的左端点恰好为 m i d mid mid 所在回文串的左端点时)
  • j j j 所在的最大回文串超出了 m i d mid mid 所在回文串的范围,则 p i = m r − i p_i=mr-i pi=mri

综上所述, p i ≥ min ⁡ ( p j , m r − i ) p_i\ge \min(p_j,mr-i) pimin(pj,mri)

  • i i i m r mr mr 的右边,即在 m i d mid mid 所在回文串的外部。那么,此时 p i ≥ 1 p_i\ge 1 pi1

最后,暴力的向外扩展即可:

while (S[i - p[i]] == S[i + p[i]]) p[i] ++;

判断当前的 p i + i p_i+i pi+i 是否超出 m r mr mr,若超出,则更新 m r mr mr m i d mid mid 即可。

A n a l y s i s o f t h e T i m e C o m p l e x i t y \mathrm{Analysis\ of\ the\ Time\ Complexity} Analysis of the Time Complexity

其实,时间复杂度就是 while 循环的执行次数(即暴力扩展的次数)。

只要执行 while 那么一定会更新 m r mr mr,且 while 执行的次数与 m r mr mr 向右扩展的数量相同。

所以 m r mr mr 总是线性向右递推的,所以总的时间复杂度为 O ( n ) O(n) O(n)

T r a n s f o r m \mathrm{Transform} Transform

刚才的算法只是解决一个字符串中奇数长度的回文串,偶数的是找不出来的。

不过,通过加一些字符可以转化为能够求出任意长度的最长回文串,具体如下:

在任意 2 2 2 个字符之间添加 1 1 1#,首尾也要加入 #,再在首尾分别加入 $^ 以防出界,因为你会发现 while 循环是没有边界的。

具体形式: $ # a 1 # a 2 # a 3 # … a n # ∧ \$ \# a_1\# a_2\# a_3\#\dots a_n\#\wedge $#a1#a2#a3#an#

这样对于新串的最长回文半径 − 1 -1 1 即为旧串最长回文串长度。

A c c e p t e d C o d e \mathrm{Accepted\ Code} Accepted Code
#include <bits/stdc++.h>
#define int long longusing namespace std;typedef pair<int, int> PII;
typedef long long LL;const int SIZE = 4e7 + 10;int N;
string A, S;
int P[SIZE];void Manacher()
{int mid, mr = 1;for (int i = 1; i <= N; i ++){if (i < mr) P[i] = min(P[mid * 2 - i], mr - i);else P[i] = 1;while (S[i - P[i]] == S[i + P[i]]) P[i] ++;if (i + P[i] > mr){mr = i + P[i];mid = i;}}
}signed main()
{cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);cin >> A;N = A.size(), A = ' ' + A;S += "$#";for (int i = 1; i <= N; i ++)S += A[i], S += '#';S += '^';N = S.size(), S = ' ' + S;Manacher();int Result = 0;for (int i = 1; i <= N; i ++)Result = max(Result, P[i] - 1);cout << Result << endl;return 0;
}

练习题:P5446 【THUPC2018】绿绿和串串

D e s c r i p t i o n \mathrm{Description} Description

定义翻转的操作:把一个串以最后一个字符作对称轴进行翻转复制。形式化地描述就是,如果他翻转的串为 R R R,那么他会将前 R − 1 R-1 R1 个字符倒序排列后,插入到串的最后

现给出字符串 S S S,询问有哪些串长度不超过 ∣ S ∣ |S| S 的串 R R R 经过若干次翻转操作后得到的串作为 T T T 的前缀。

数据范围: ∑ ∣ S ∣ ≤ 5 × 1 0 6 \sum|S|\le 5\times 10^6 S5×106

S o l u t i o n \mathrm{Solution} Solution

考虑怎样的串翻转若干次之后前缀包含 S S S,其一定是 S S S 的一个前缀,这样翻转后 S S S 才会是它的前缀。

那么,对于 S S S 中每一个位置 i i i 分情况讨论:

  • 1 ∼ i 1\sim i 1i 的串翻转 1 1 1 次之后长度超过 ∣ S ∣ |S| S,则要求 i + 1 ∼ ∣ S ∣ i+1\sim |S| i+1S 的串是 1 ∼ i − 1 1\sim i-1 1i1 的串取反后的前缀,即以 i i i 为中心的回文串最大右端点为 ∣ S ∣ |S| S。标记 i i i 位置为可行位置。
  • 1 ∼ i 1\sim i 1i 的串翻转 1 1 1 次之后长度小于 ∣ S ∣ |S| S,则要求 1 ∼ 2 i − 1 1\sim 2i-1 12i1 是回文串,且右端点为可行位置,也就是能够经过多次翻转使 S S S 为其的前缀。

A c c e p t e d C o d e \mathrm{Accepted\ Code} Accepted Code

#include <bits/stdc++.h>
#define int long longusing namespace std;typedef pair<int, int> PII;
typedef long long LL;const int SIZE = 2e6 + 10;int N;
string S;
int P[SIZE], Vis[SIZE];void Manacher()
{int mr = 1, mid;for (int i = 1; i <= N; i ++){if (i < mr) P[i] = min(P[mid * 2 - i], mr - i);else P[i] = 1;while (S[i - P[i]] == S[i + P[i]]) P[i] ++;if (P[i] + i > mr)mr = P[i] + i, mid = i;}
}void solve()
{cin >> S;N = S.size(), S = ' ' + S, S += '^';Manacher();for (int i = N; i >= 1; i --)if (i + P[i] - 1 >= N) Vis[i] = 1;else if (Vis[i + P[i] - 1] && i - P[i] + 1 == 1) Vis[i] = 1;for (int i = 1; i <= N; i ++)if (Vis[i])cout << i << " ", Vis[i] = 0;cout << endl;
}signed main()
{cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);int Data;cin >> Data;while (Data --)solve();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/692431.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用智能电销机器人,拓客效果更佳!

现在很多的企业做销售都离不开电话营销&#xff0c;它是一种能够直接帮助企业获取更多利润的营销模式&#xff0c;目前被各大行业所采用。 znyx222 了解探讨 电话营销是一个压力很大的职业&#xff0c;新员工培养难度大、老员工又不好维护&#xff0c;会有情绪问题出现等&…

blasterswap明牌空投

空投要点 明牌空投&#xff0c;blaster生态第一个swap&#xff0c;应该不会寒酸交互简单&#xff0c;仅需3步&#xff0c;零gas费仅仅要求加密钱包在eth链有过交易需要有x和discord账号 blasterswap空投简介 BlasterSwap 是Blast生态里面第一个SWAP项目&#xff0c;近期启动…

【嵌入式学习】QT-Day1-Qt基础

笔记 https://lingjun.life/wiki/EmbeddedNote/20QT 毛玻璃登录界面实现&#xff1a;

Fisher-Yates乱序算法

乱序算法 public class Test07 {public static void main(String[] args) {//乱序算法int[] arr {1,2,3,4,5,6,7,8};//逆序遍历 且这个随机的下标不能使要交换的元素的本身for(int i arr.length-1;i>0;i--){//产生一个随机的下标与当前元素进行交换int index (int)(Math…

智慧公厕管理系统:让城市智慧驿站更加智慧舒适

智慧公厕管理系统是城市智慧驿站中不可或缺的一部分&#xff0c;它通过全方位的信息化解决方案&#xff0c;为公共厕所的使用、运营和管理提供了一种智能化的方式。作为城市智慧驿站的重要组成部分&#xff0c;智慧公厕管理系统发挥着重要的作用&#xff0c;为城市社会民生提供…

RuntimeError: CUDA out of memory.【多种场景下的解决方案】

RuntimeError: CUDA out of memory.【多种场景下的解决方案】 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;【Matplotlib之旅&#xff1a;零基础精通数据可视化】 &#x1f3c6;&#x1f3c6;关注博主&#xff0c;随时获取更多关于深度学…

SQL Developer 小贴士:显示Trace文件

SQL Developer可以识别trace文件&#xff0c;而无需利用tkprof进行转换。 在数据库服务器上生产trace文件。例如&#xff1a; alter session set tracefile_identifierdemo01_02;alter session set sql_tracetrue;-- your SQL here, for example select * from hr.employees;a…

防御第六次作业-防火墙综合实验(av、url过滤、dns过滤)

目录 拓扑图&#xff1a; 要求&#xff1a; 8 9 10 11 拓扑图 要求 前7个要求在上一篇博客&#xff1b; 8.分公司内部的客户端可以通过域名访问到内部的服务器 9.假设内网用户需要通过外网的web服务器和pop3邮件服务器下载文件和邮件&#xff0c;内网的FTP服务器也需要…

【Redis高手修炼之路】④主从复制

主从复制 就是 redis集群的策略配从&#xff08;库&#xff09;不配主&#xff08;库&#xff09;&#xff1a;小弟可以选择谁是大哥&#xff0c;但大哥没有权利去选择小弟读写分离&#xff1a;主机写&#xff0c;从机读 一主二仆 准备三台服务器&#xff0c;并修改redis.co…

Spin Image特征描述子简介

一、向量点积 二、狄拉克δ函数公式 三、Spin Image特征描述子原理 Spin Image自旋图像描述符可视化以及ICP配准-CSDN博客

C++结合Lambda表达式在函数内部实现递归

529. 扫雷游戏 已解答 中等 相关标签 相关企业 让我们一起来玩扫雷游戏&#xff01; 给你一个大小为 m x n 二维字符矩阵 board &#xff0c;表示扫雷游戏的盘面&#xff0c;其中&#xff1a; M 代表一个 未挖出的 地雷&#xff0c;E 代表一个 未挖出的 空方块&#xff…

【XR806开发板试用】+移植rosserial到XR806

1 XR806简介 板子来源于极术社区的试用&#xff0c;XR806的在线网址 其主要参数&#xff1a; 主控XR806AF2LDDRSIP 288KB SRAM存储SIP 160KB Code ROM. SIP 16Mbit Flash.天线板载WiFi/BT双天线&#xff0c;可共存按键reboot按键 1&#xff0c;功能按键 1灯红色电源指示灯 1…

测试开发【Mock平台】14基础:拦截器服务实现(五) 规则查询代码

【Mock平台】为系列测试开发教程&#xff0c;从0到1编码带你一步步使用Spring Boot 和 Antd React框架完成搭建一个测试工具平台&#xff0c;希望作为一个实战项目对各位的测试开发学习之路有帮助&#xff0c;关注公众号发送“mock”获取github项目源码地址&#xff0c;大奇一个…

ctfshow-web29~40-WP

web29 if(isset($_GET[c])){$c = $_GET[c];if(!preg_match("/flag/i", $c)){eval($c);}}else{highlight_file(__FILE__); } 首先先system(“ls”);查看一下文件 既然过滤了flag,那我们就fla*的形式进行匹配,结合tac命令输出flag.php文件内容

拿捏c语言指针(下)

前言 此篇讲解的主要是函数与指针的那些事~ 书接上回 拿捏c语言指针&#xff08;上&#xff09;和 拿捏c语言指针&#xff08;中&#xff09; ​​​​​​没有看的小伙伴要抓紧喽~ 欢迎关注​​个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#x…

有哪些好用的网页原型网站?

与桌面端相比&#xff0c;在线网页原型网站的使用具有优势&#xff0c;因为在线网页原型网站在整个使用过程中不需要安装&#xff0c;在线网页原型网站在任何地方都没有限制。更重要的是&#xff0c;无论是现在使用的Linux&#xff0c;在线网页原型网站在操作系统中都没有限制、…

一.重新回炉Spring Framework: 理解Spring IoC

1. 写在前面的话 说实话&#xff0c;从事java开发工作时间也不短了&#xff0c;对于Spring Framework&#xff0c;也是天天用&#xff0c;这期间也碰到了很多问题&#xff0c;也解决了很多问题。可是&#xff0c;总感觉对Spring Framework还是一知半解&#xff0c;不能有个更加…

苍穹外卖学习-----2024/02/19

1.开发环境搭建 我的git截图我使用的datagrip 运行sql学习到jwt令牌一种新的配置方式&#xff0c;写配置文件学习到了build属性nginx解决跨域的问题2.导入接口的文档 结果如图所示 3.Swagger /*** 通过knife4j生成接口文档* return*/Beanpublic Docket docket() {ApiInfo api…

深度学习基础——卷积神经网络(一)

卷积操作与自定义算子开发 卷积是卷积神经网络中的基本操作&#xff0c;对于图像的特征提取有着关键的作用&#xff0c;本文首先介绍卷积的基本原理与作用&#xff0c;然后通过编写程序实现卷积操作&#xff0c;并展示了均值、高斯与sobel等几种经典卷积核的卷积效果&#xff…

kafka的安装,用于数据库同步数据

1.0 背景调研 因业务需求&#xff0c;需要查询其他部门的数据库数据&#xff0c;不方便直连数据库&#xff0c;所以要定时将他们的数据同步到我们的环境中&#xff0c;技术选型选中了kafkaCDC Kafka是Apache旗下的一款分布式流媒体平台&#xff0c;Kafka是一种高吞吐量、持久…