热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Manacher算法:寻找最长回文子串长度的高效算法

本文介绍了Manacher算法,一种用于寻找字符串中最长回文子串长度的高效算法。该算法的复杂度为O(N),并且解决了需要分情况讨论的问题。文章详细介绍了Manacher算法的思路和实现方式,并且给出了一个示例。此外,还介绍了Len数组的含义和使用方法。对于对字符串处理感兴趣的读者,本文也推荐了一篇思路清晰、简单易懂的博客。

(本文最后判断区间回文有改动,emm之前写错了,你这么聪明一定看出来了)

该算法用于寻找当前串中最长的回文子串长度。

为了避免误人子弟,也可以直接去看思路清晰,简单易懂的博客:https://blog.csdn.net/dyx404514/article/details/42061017

这个大神写的各种算法的模板和讲解都很棒哦。

①暴力找:

我们选取一个点O,然后要考虑这个点作为回文串中心可能形成最长回文串的三种情况:

回文长度为奇数的情况

xxOxx

回文长度为偶数的情况:

xxxOxx

xxOxxx

O(N²)的复杂度妥妥的。


②Manacher:

首先该算法是O(N)的。

然后解决了上述需要分三种情况讨论的问题。

假设一个待匹配的串为aabaa

我们会把他变成

¥#a#a#b#a#a#$

也就是用(字符串长度+1个)#把字符一个个分开,旁边再加两个不同的字符防止匹配的时候越界。

为什么这样处理就可以不用分情况了呢?

这个问题我们在构造好了我们的Len数组,了解这个数组的含义了之后再说。

我们对这个船新的串使用manacher算法


③Len数组含义与构造:

Len[i]表示以i为中心的回文串往右边延伸了多少

eg:¥#a#a#b#a#a#$,Len【6】 =  6,Len【2】= 2 ,Len【1】 = 1

构造核心思想与kmp,exkmp差不多,就是根据已经匹配的,让当前能够最大限度的偷懒(得到当前已知匹配的部分)

PO表示当前Len能够向右延伸最远的回文串中点坐标。

mx就是延伸最右位置的坐标。

这两个都是辅助用于判断当前i位置有几位已经确定回文可以不用比了。

具体匹配过程的图示:(红色块最右即为mx)

板子:(主函数 字符串从0开始输入)

const int maxn=1000010;
char str[maxn];//原字符串
char tmp[maxn<<1];//转换后的字符串
int Len[maxn<<1];
//转换原始串
int INIT(char *st)
{int i,len&#61;strlen(st);tmp[0]&#61;&#39;&#64;&#39;;///开头加一个不等于#也不等于字符串的字符&#xff0c;这样就不用判断左边越界了&#xff0c;那么右边万一比到n&#43;1怎么办呢&#xff1f;有\0吗&#xff1f;不&#xff0c;\0在n处&#xff0c;解决办法看16行for(i&#61;1;i<&#61;2*len;i&#43;&#61;2){tmp[i]&#61;&#39;#&#39;;tmp[i&#43;1]&#61;st[i/2];}tmp[2*len&#43;1]&#61;&#39;#&#39;;tmp[2*len&#43;2]&#61;&#39;$&#39;;///结尾搞一个不是&#64;也不是#的字符tmp[2*len&#43;3]&#61;0;return 2*len&#43;1;//返回转换字符串的长度
}
//Manacher算法计算过程
int MANACHER(char *st,int len)
{int mx&#61;0,ans&#61;0,po&#61;0;//mx即为当前计算回文串最右边字符的最大值for(int i&#61;1;i<&#61;len;i&#43;&#43;){if(mx>i)Len[i]&#61;min(mx-i,Len[2*po-i]);//在Len[j]和mx-i中取个小elseLen[i]&#61;1;//如果i>&#61;mx&#xff0c;要从头开始匹配while(st[i-Len[i]]&#61;&#61;st[i&#43;Len[i]])Len[i]&#43;&#43;;if(Len[i]&#43;i>mx)//若新计算的回文串右端点位置大于mx&#xff0c;要更新po和mx的值{mx&#61;Len[i]&#43;i;po&#61;i;}ans&#61;max(ans,Len[i]);}return ans-1;//返回Len[i]中的最大值-1即为原串的最长回文子串额长度
}

实在理解不了去看看exkmp&#xff0c;真的感觉是一毛一样的&#xff1a;https://blog.csdn.net/weixin_43768644/article/details/94644776


④&#xff1a;Len数组的使用

注意Len数组使用是都是看原字符串第几个字符&#xff08;1~n&#xff09;&#xff0c;不是看下标&#xff08;0~i-1&#xff09;&#xff0c;这个比较重要

&#xff08;0&#xff09;基本的认识

         Len[i]对应两种情况&#xff1a;

         ①当前是‘#’时&#xff0c;Len[i] 必定为奇数&#xff0c;eg&#xff1a;a#a  #  a#b&#xff0c;Len[中间&#39;#&#39;的下标] &#61; 3

         那么这个Len[i]就对应原字符串中偶数长度的回文串&#xff0c;你可以求原串的回文中点&#xff08;i/2表示靠左的中点&#xff09;&#xff0c;然后最大回文半径

         等于Len[i]/2     &#xff08;因为奇数会向下取整&#xff09;

         ②当前是字母&#xff0c;Len[i]比为偶数&#xff0c;eg&#xff1a;a#a# b #a#b 对应奇数长度回文串&#xff0c;i/2表回文中点&#xff0c;Len[中间&#39;b&#39;的下标] &#61; 4

         i/2是回文中心&#xff0c;Len[i]/2是回文半径&#xff08;&#61;2&#xff0c;对于aba&#xff09;

         下面这三个应该没什么用。

         i表示第i个字符

         判断当前点作为奇数长度回文中点的最长回文长度  --->Len[i*2]-1

         判断当前点作为偶数长度回文左中点的最长回文长度  --->Len[i*2&#43;1]-1

         判断当前点作为偶数长度回文左中点的最长回文长度  --->Len[i*2-1]-1

&#xff08;1&#xff09;判断原字符串中[l,r]是否回文&#xff08;l&#xff0c;r表示第几个字母&#xff09;

         Len[l&#43;r]-1>&#61;r-l&#43;1    &#xff1f;  是回文&#xff1a;不是回文

         证明方法&#xff1a;根据给出区间长度奇偶分类&#xff0c;运用&#xff08;0&#xff09;里面的基本知识判断就可以

&#xff08;2&#xff09;求出整个串的回文串总数

         根据&#xff08;0&#xff09;所说的&#xff0c;遍历加了‘#’的那个串分析每个点做中点的最长回文半径即可

&#xff08;3&#xff09;求出本质不同的回文串的数量

         分析&#xff1a;首先每一个点开始匹配前会先尽可能得到已知匹配部分来减少当前匹配&#xff0c;然后这部分我们不用判断是否出现过&#xff0c;因为肯定出现过。然后剩余要匹配部分&#xff0c;每次都对新产生这个回文串判断是否出现过&#xff0c;&#xff08;可能出现也可能没出现过&#xff09;&#xff0c;马拉车&#43;哈希表去重即可实现。&#xff08;模板题&#xff1a;hihocoder1602&#xff09;

做这些事情的复杂度和耗费的空间都比回文自动机小&#xff08;大概&#xff09;&#xff0c;然后处理回文问题两者要灵活结合使用。


推荐阅读
  • 在解决区间相关问题时,我发现自己经常缺乏有效的思维方式,即使是简单的题目也常常需要很长时间才能找到解题思路,而一旦得到提示便能迅速理解。题目要求对一个包含n个元素的数组进行操作,并给出一个参数k,具体任务是…… ... [详细]
  • Golomb 编码是一种高效的变长编码技术,专门用于整数的压缩。该方法通过预定义的参数 \( M \) 将输入整数分解为商 \( q \) 和余数 \( r \) 两部分。具体而言,输入整数除以 \( M \) 得到商 \( q \) 和余数 \( r \),其中商 \( q \) 采用一元编码表示,而余数 \( r \) 则使用二进制编码。这种编码方式在数据压缩和信息传输中具有显著的优势,特别是在处理具有特定概率分布的数据时表现出色。 ... [详细]
  • 如何在Lua中调用C语言编译的动态链接库
    本文介绍了如何在Lua中调用C语言编译的动态链接库。通过详细步骤和示例代码,帮助开发者理解和掌握这一技术。参考了《Lua编程入门》一书中的相关内容,并结合实际操作经验,提供了更加清晰和实用的指导。此外,还探讨了在不同操作系统下编译和链接Lua的方法,为跨平台开发提供了有价值的参考。 ... [详细]
  • 本文提出了一种高效的数据结构与算法,旨在解决超大整数(超出常规 `long` 类型范围)的加法运算问题。通过引入自定义的数据结构,该方法能够有效地存储和处理任意大小的整数,并在保证计算精度的同时,显著提升运算效率。实验结果表明,该方法在处理大规模数据时表现出色,具有较高的实用价值。 ... [详细]
  • 针对NOJ1102黑白图像问题,本文采用深度优先搜索算法进行详细分析与实现。该问题要求在给定的时间限制(普通Java为1000-3000毫秒)和内存限制(65536KByte)内,处理一个n×n的黑白图像。通过对图像的逐像素遍历,利用深度优先搜索算法有效地识别并标记相连的黑色区域,从而实现图像的高效处理。实验结果显示,该方法在多种测试用例中均能稳定达到预期效果,具有较高的准确性和效率。 ... [详细]
  • 本文深入解析了计算力扣平台上汉明距离问题的官方解法,并通过优化算法提高了计算效率。具体而言,我们详细探讨了如何利用位运算技巧来高效计算数组中所有数对之间的汉明距离,从而在时间和空间复杂度上实现了显著改进。通过实例代码演示,使读者能够更直观地理解这一优化方法。 ... [详细]
  • 题目链接:POJ 2777。问题描述:给定一个区域,需要进行多次涂色操作,并在每次操作后查询某个区间内的不同颜色数量。解决方案:由于题目中颜色种类不超过30种,可以利用线段树的懒惰更新策略来高效处理这些操作。通过懒惰标记,避免了不必要的节点更新,从而显著提高了算法的效率。此外,该方法还能有效应对大规模数据输入,确保在合理的时间内完成所有操作。 ... [详细]
  • 在晴朗天气条件下,对一种神奇的魔法现象进行了深入分析。该题目为原创,基准时间限制为1秒,空间限制为131072KB,分值20,属于3级难度的算法题。研究发现,这种魔法现象在阳光明媚的环境中表现得尤为显著,进一步探讨了其背后的科学原理和技术实现方法。 ... [详细]
  • 如何在Excel中使用LINEST函数进行多元线性回归分析?
    LINEST函数利用最小二乘法计算与现有数据最佳拟合的直线,从而得出直线的统计值,并返回描述该直线的数组。此外,LINEST函数还可以与其他函数配合使用,以实现更复杂的多元线性回归分析。通过合理运用LINEST函数,用户可以在Excel中高效地进行数据分析和预测建模。 ... [详细]
  • 每日精选Codeforces训练题:1119E(贪心算法)、821C(栈模拟)和645D(拓扑排序)
    题目涉及三种不同类型的算法问题:1119E(贪心算法)、821C(栈模拟)和645D(拓扑排序)。其中,1119E的问题背景是有n种不同长度的棍子,长度分别为2^0, 2^1, …, 2^(n-1),每种棍子的数量为a[i]。任务是计算可以组成的三角形数量。根据三角形的性质,任意两边之和必须大于第三边。该问题可以通过贪心算法高效解决,通过合理选择棍子组合来最大化三角形的数量。 ... [详细]
  • C语言中fprintf函数写入文件出现空白问题及解决方法
    C语言中fprintf函数写入文件出现空白问题及解决方法 ... [详细]
  • Redis哈希数据结构入门指南
    Redis的哈希数据结构与Java中的HashMap类似,采用数组加链表的方式实现。数组用于存储哈希值的位置,而链表则用于处理哈希冲突的情况。此外,Redis的哈希数据结构还支持高效的字段操作和内存优化,适用于多种应用场景,如缓存和会话管理。 ... [详细]
  • 数组容量的动态调整与优化策略
    在探讨数组容量动态调整与优化策略时,本文分析了两种常见的方法。首先,通过使用for循环逐个复制元素实现扩容,但这种方法存在计算索引的复杂性问题。其次,利用System.arraycopy()方法进行高效复制,显著提升了性能和代码可读性。此外,文章还讨论了动态数组在不同应用场景下的优化策略,包括预分配容量和按需扩展等技术,以提高程序的整体效率。 ... [详细]
  • 如何利用正则表达式(regexp)实现高效的模式匹配?本文探讨了正则表达式在编程中的应用,并分析了一个示例程序中存在的问题。通过具体的代码示例,指出该程序在定义和使用正则表达式时的不当之处,旨在帮助读者更好地理解和应用正则表达式技术。 ... [详细]
  • Java 模式原型在游戏服务器架构中的应用与优化 ... [详细]
author-avatar
漫路细雨中_575
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有