当前位置: 首页 > news >正文

36.Manacher 算法

一、基本介绍

本节我们将介绍一种算法来解决一类关于回文字符串的问题。给定一个长度为 nnn 的字符串 sss,请找到所有使得子串 s[i…j]s[i \dots j]s[ij] 为一个回文串的二元组 (i,j)(i, j)(i,j)。当 s=srevs=s_{\text{rev}}s=srev 时,我们说字符串 sss 是一个回文串,srevs_{\text{rev}}srev 被定义为 sss 的反转字符串。

本节所要讲的算法名叫 Manacher 算法,它是一个能够在线性时间内得到一个字符串中最长回文子串的算法,性能比其他的算法,如字符串哈希还要优秀,且不会被特殊数据卡住。Manacher 算法的核心思想和 KMP 算法非常相似,都是利用已经计算过的信息来加快字符串的匹配进程。目前 Manacher 算法是处理回文串最有效的工具之一。

二、算法分析

我们可以知道在最坏情况下,例如对于字符串 s=aaaa...as=aaaa...as=aaaa...a 来说有 n2n^2n2​ 个回文串,因此该问题似乎并无线性算法。首先我们面临一个问题,那就是我们如何处理奇数回文串和偶数回文串这两种不同情况。我们可以采取如下处理方式:

  • 假设存在一个长度为奇数的字符串 str=abbabbastr=abbabbastr=abbabba
  • 我们可以将其转化为一个新的字符串 s=∗@a@b@b@a@b@b@a@!s=*@a@b@b@a@b@b@a@!s=@a@b@b@a@b@b@a@!
  • 原则是首尾两个字符不同,和中间的字符也不同(防止出现访问越界),中间所有字符相同。

1.求解最终答案

为了引出 Manacher 算法 我们下面给出一种关于回文串的信息的更紧凑表达方式:对于每个位置 i=0…n−1i=0 \dots n-1i=0n1,我们找出值 d[i]d[i]d[i]d[i]d[i]d[i] 表示以位置 iii 为中心的回文串个数。换个角度,二者也表示了以位置 iii 为中心的最长回文串的半径长度(半径长度 d[i]d[i]d[i] 为从位置 iii 到回文串最右端位置包含的字符个数。与此同时 d[i]d[i]d[i] 也可以表示以 iii 为中心的最长回文串的长度。

我们首先考虑下面我们给出一个结论,ans=d[i]−1ans=d[i]-1ans=d[i]1,我们在这里以举例的方式简单说明,现在我们来观察一下这个新字符串 sss

  • 以我们的 s[8]=as[8]=as[8]=a 为中心的回文串向右最大拓展长度 +1+1+1 即为 d[8]=8d[8]=8d[8]=8,而回到原字符串,我们知道以 str[3]str[3]str[3] 为中心的最大回文字串长度为 7=d[8]−17=d[8]-17=d[8]1
  • 以我们的 s[5]=@s[5]=@s[5]=@ 为中心的回文串向右最大拓展长度 +1+1+1 即为 d[5]=5d[5]=5d[5]=5,而回到原字符串,我们知道以 str[1,2]str[1,2]str[1,2] 为中心的最大回文字串长度为 4=d[5]−14=d[5]-14=d[5]1
  • 由此可以得到结论,ans=max⁡(d[i]−1)ans=\max(d[i]-1)ans=max(d[i]1)

2.求解数组 d[i]d[i]d[i]

下面我们来介绍应该如何求解数组 d[i]d[i]d[i],也就是 Manacher 算法的核心部分。假设此时我们已经得到 d[0]∼d[i−1]d[0]\sim d[i-1]d[0]d[i1],那么现在来求 d[i]d[i]d[i]

现在我们结合下图来做具体分析:

在这里插入图片描述

  • mxmxmx 表示前面的所有结果中向右扩展得最多的 dddididid 表示 mxmxmx 对应的中心字符位置。

  • 因为 i≥mxi\geq mximx 时很简单,我们只需要暴力拓展即可,因为后面的都是未计算内容。下面我们只分析 i<mxi<mxi<mx 的情况。

  • 我们可以找到 iii 关于 ididid 的对称点 i′=2⋅id−ii'=2\cdot id-ii=2idi,而 d[i′]d[i']d[i] 我们是知道的(即绿色弧线部分),根据对称性,理想的回文即为绿色部分。

  • 如果 i+d[i′]>mxi+d[i']>mxi+d[i]>mx,那么 d[i]=mx−id[i]=mx-id[i]=mxi。因为超过的部分(即红色区块)根据关于 ididid 的对称性可知道是以 ididid 为中心的回文串没有拓展到的位置,因为 mxmxmx 就是最大拓展,即说明不对称。而根据定义在 mxmxmx 以内是满足对称的(即蓝色区块),所以 d[i]=mx−id[i]=mx-id[i]=mxi

  • 而当 i+d[i′]≤mxi+d[i'] \leq mxi+d[i]mx 时,显然这时候以 ididid 为中心,mxmxmx 为半径的字串是对称的。i+d[i′]i+d[i']i+d[i] 被包含在这个区间内,而 i+d[i]i+d[i]i+d[i]mxmxmx 中间部分无法计入答案的原因是,根据对称性,i′i'i 无法匹配到,那么iii也无法匹配到。所以 d[i]=d[i′]d[i]=d[i']d[i]=d[i]

所以综上所述,在 i<mxi<mxi<mx 时,d[i]=min⁡(mx−i,d[2⋅id−i])d[i]=\min(mx-i,d[2\cdot id-i])d[i]=min(mxi,d[2idi])。下面是核心代码:

d[0]=0;
ll mx = 0, ans = 0, id = 0;
for(ll i = 1; i < count1; i++)
{if(i < mx)d[i] = min(mx - i, d[2 * id - i]);elsed[i] = 1;while(s[i - d[i]] == s[i + d[i]])d[i]++;if(i + d[i] > mx){mx = d[i] + i;id = i;ans = max(ans, d[i] - 1);}
}

三、作业

1.绿题

UVA11475 Extend to Palindrome

2.蓝题

P1659 [国家集训队] 拉拉队排练

P3501 [POI 2010] ANT-Antisymmetry

http://www.dtcms.com/a/305400.html

相关文章:

  • 【n8n】如何跟着AI学习n8n【01】:定制AI老师
  • 【Linux】pthread学习笔记
  • scrapy框架新浪新闻
  • 使用JSON Schema 的 dependencies 实现 LLM 工具调用的参数约束
  • C 语言基础第16天:指针补充
  • 粒子群优化算法(Particle Swarm Optimization, PSO) 求解二维 Rastrigin 函数最小值问题
  • Mysql缓冲池和LRU
  • 关注 Yocto项目实战教程
  • PyCharm插件开发与定制指南:打造个性化开发环境
  • C++ 模板类型传递可行性检测指南
  • 3D打印喷头的基本结构
  • 区间DP求解策略详解
  • cmseasy靶机密码爆破通关教程
  • 第一章 RAG三问
  • flask使用celery通过数据库定时
  • 【专题十六】BFS 解决最短路径
  • Qt制作一个简单通信程序
  • C语言---万能指针(void *)、查找子串(strncmp函数的应用)多维数组(一维数组指针、二维数组指针)、返回指针值函数、关键字(const)
  • MongoDB系列教程-第一章:MongoDB简介、安装 、概念解析、用户管理、连接、实际应用示例
  • 数据结构-图的相关定义
  • 猎豹移动宣布控股UFACTORY,合计持股超80%
  • Oracle优化学习十六
  • Java高级技术知识点
  • 书籍推荐算法研究
  • 分布式链路追踪的实现原理
  • 系统学习算法:专题十五 哈希表
  • 第十一天:不定方程求解
  • windows下Docker安装路径、存储路径修改
  • LeetCode 刷题【19. 删除链表的倒数第 N 个结点、20. 有效的括号、21. 合并两个有序链表】
  • Ragflow 文档处理深度解析:从解析到存储的完整流程