【Manacher算法】最长子回文串
【Manacher算法】
这个算法用来找出一个字符串中最长的回文子字符串。
如果采取暴力解最长回文子字符串问题,大概可以有两种思路:1. 遍历出所有子字符串找其中最长的回文 2. 从每个字符作为中心,向两边扩散看是否回文。 第二种比第一种稍微高明一点,但是总体的复杂度还是O(n^2)的。
而Manacher算法可以做到O(n)时间复杂度,O(n)空间复杂度。
■ 思路&描述
回文字符串有一个比较麻烦的地方,就是回文串有偶回文和奇回文两种,分别举例ABBA和ABCBA。这种区别可能要让我们在程序中额外伸出一个判断分支来,不是很方便。所以Manacher算法的第一步就是预处理字符串,将原先的字符串所有字符中间再加上头尾两端都加上一个特殊符号,这样就可以把所有可能的回文串都变成了奇回文串,方便处理:
如ABBA变成#A#B#B#A#,ABCBA变成#A#B#C#B#A#。此外,一般实践中为了保证边界上也能统一,还会额外在头上(理论上字符串尾也可以加,但是目前尾巴上肯定是#,大不了我们遍历的时候最后这轮以这个#字符为基础的遍历不去做了,这样就可以避免尾部边界出错)加上一个$或者其他有别于#的特殊符号表示字符串的开始。经过这样预处理之后的字符串可以拿来被manacher算法处理。
接下来,基本思路肯定还是要找出以每个字符为中心时,回文串最长可以做到多少。只是一个个去遍历太暴力了,这里可以借鉴一下动态规划中的一点小心思,也就是说我们能不能利用已有的信息(当然这部分信息是需要在之前的分析过程中手动保存下来的)来更加方便地推出我们未知的信息。
比如我们可以创建一个数组p,针对被加工过字符串s,p的长度被设定为和s等长,且p中保存的内容,是以对应原s字符串中那个字符为中心,其最大回文子字符串的半径长度。由于s中所有回文串都是奇回文串,所以我们所说的半径是指从回文串的左端开始到中心(算入中心)的长度。如#a#b#a#的半径是4,#a#b#b#a#的半径是5。
那么如何基于一些现有信息推断新的信息呢?考虑这样一种情形:假如我们以i变量作为向右遍历的下标,逐渐向右遍历确定了一个回文子串。这个子串的中心和半径两个参数都是可以明确的。不妨称中心的下标为id,称回文串最右端下标为mx(这也是后续编码过程中需要使用的两个辅助变量)。确定完id和mx之后我们继续往右推移i。
当我们来到一个新的i时,如果它还在mx范围内,此时可以注意到,其实存在一个点j,j和i关于id对称,由于id,mx的回文特性,所以j的回文串很大可能就是i的回文串。这种可能成为确定只需要一个条件,那就是p[j]的取值,没有超出id,mx这个回文串的范围。下面是盗来的图,说明了i,j,id,mx以及mx'(mx关于id的对称点)的布局。
那么如果p[j] > j - mx',即j对应的回文串已经超出了mx的范围,此时改怎么办?很显然,在mx'到j的这段内容,由于id,mx的回文性,还是可以对应到i到mx这段内容的。至于mx之后的内容,只能再去一个个字符遍历过去看能不能符合回文。
总的来说,当i仍然小于mx时,i的取值应该可以取min(p[j],mx-i),当取p[j]的时候,p[i]就是p[j]的值。当取mx-i的时候,mx-i还只是一个基础值,还需要进一步处理来获得准确值。
还没有讨论完,刚才说的都是i<mx的情况,如果此时已经遍历到超过mx了怎么办?此时由于没有任何既存的回文串性质可以利用,所以只能老老实实向外一个个字符扩散判断回文性。比较好的一点是,之前讨论过的关于i<mx的两种取值可能,也都可以(或必要)做这个扩散。
为了保证递推的连续性,不论上上述哪种可能,获得到i的回文串之后,都需要将id和mx进行更新。应该注意,id和mx并不是我们最后要求的最长回文子串的属性,而只是当前已经遍历过的最靠右的一个回文子串的属性。
而要求最长回文子串的属性我们可以再维护一个类似于longestInfo之类的变量,每找出一个回文子串后判断它是不是最长的。所有循环结束后去这个变量里面取值就好了。
■ 编码实现
下面是manacher算法的python实现:
def longestPalindrome(s):
"""
:type s: str
:rtype: str
"""
s = '$#' + '#'.join(list(s)) + '#' # 预处理
p = [0] * len(s)
longestInfo = [0,0]
i,currRes,currMax = 1,0,0 # 由于s[0]是$,所以i从1开始取值。id和mx分别换了个名字currRes和currMax
while i < len(s):
if i > currMax: # i已经超出mx的情况
p[i] = 1
else: # i未超出mx,再分成两种情况,体现在min函数中
j = 2*currRes - i
p[i] = min(p[j],currMax-i)
# 此时p[i]并不一定已经正确,除了决定p[i]=p[j],其他两个分支都只是给了p[i]一个基准值
while i-p[i]>0 and i+p[i]<len(s) and s[i-p[i]] == s[i+p[i]]:
# 进行一个个字符向外扩散的回文性检查
# 注意为了防止越界访问,还要有边界判断条件
p[i] += 1
# 这时p[i]才得到了最终确定的值 接下来就是将其相关属性与已有的currRes和currMax比较,看是否需要更新
if i + p[i] > currMax:
# 更新id和max
currRes = i
currMax = i + p[i] - 1 if p[i] > longestInfo[1]:
# 更新最终结果值
longestInfo = i,p[i] i += 1
center = longestInfo[0]
radius = longestInfo[1] - 1 # 注意,半径把对称中心本身算进去了,所以减一
return s[center-radius:center+radius+1].replace('#','') # 直接replace去掉所有辅助字符,得到的就是原字符串的结果了。
【Manacher算法】最长子回文串的更多相关文章
- Manacher 算法-----o(n)回文串算法
回文的含义是:正着看和倒着看相同,如abba和yyxyy Manacher算法基本要点:用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插 ...
- manacher算法,求回文串
用来求字符串最长回文串或者回文串的总数量 #include<map> #include<queue> #include<stack> #include<cma ...
- Manacher算法,最长回文串
给你10000长度字符串,然你求最长回文字串,输出长度,暴力算法肯定超时 #include <iostream> #include <string> #include < ...
- Manacher 计算最长回文串
转自 http://blog.sina.com.cn/s/blog_3fe961ae0101iwc2.html 寻找字符串中的回文,有特定的算法来解决,也是本文的主题:Manacher算法,其时间复杂 ...
- Manacher算法——最长回文子串
一.相关介绍 最长回文子串 s="abcd", 最长回文长度为 1,即a或b或c或d s="ababa", 最长回文长度为 5,即ababa s="a ...
- POJ 3376 Finding Palindromes(manacher求前后缀回文串+trie)
题目链接:http://poj.org/problem?id=3376 题目大意:给你n个字符串,这n个字符串可以两两组合形成n*n个字符串,求这些字符串中有几个是回文串. 解题思路:思路参考了这里: ...
- Manacher(最长镜面回文串)
I - O'My! Gym - 101350I Note: this is a harder version of Mirrored string I. The gorillas have recen ...
- Manacher(最长回文串)
http://acm.hdu.edu.cn/showproblem.php?pid=3068 最长回文 Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符 ...
- Manacher算法----最长回文子串
题目描述 给定一个字符串,求它的最长回文子串的长度. 分析与解法 最容易想到的办法是枚举所有的子串,分别判断其是否为回文.这个思路初看起来是正确的,但却做了很多无用功,如果一个长的子串包含另一个短一些 ...
随机推荐
- 潭州课堂25班:Ph201805201 django框架 第七课 常用 字段类型及参数,关系表的实现,表关系对象add,create的方法 (课堂笔记)
写个类,创建表格 执行命令生成文件 提交,在数据库中创建 进入数据库查看 对数据进行修改操作 只有用到 save() 才能触发 updaer_time 的更改, 下边 update 方法不会修改 up ...
- Win10+Ubuntu 二三事
拯救者R720,反反复复弄了不少次,记录一下有用的blog 卸载 http://www.cnblogs.com/xia-Autumn/p/6294055.html https://blog.csdn. ...
- 转 What is Redis and what do I use it for?
原文: http://stackoverflow.com/questions/7888880/what-is-redis-and-what-do-i-use-it-for Redis = Remote ...
- HDFS JournalNode 故障
背景 某天凌晨四点左右,HBase RegionServer 宕机自动拉起,查看日志发现是HDFS 在进行HA切换,15次重试仍连不上可写的active,于是挂了.所以根本问题是hdfs. 日志定位 ...
- REST风格的增删改查(2)
一.源码 1.页面 index.jsp <a href="emps">List All Employee</a> <br><br> ...
- 大神们都在用的两个国外的免费离线下载:Rain& LoadBT
大神们都在用的两个国外的免费离线下载:Rain& LoadBT 最近QQ离线和迅雷离线也都挂了,115还死贵,所以分享两个国外免费的网站.希望可以为大家提供一些帮助,同时也借此机会同大家相互交 ...
- 招聘移动APP、接口、自动化、性能和安全方面的兼职测试讲师
只要您在移动APP.接口.自动化.性能和安全方面有丰富的测试经验,我们都欢迎您能加入我们,成为我们的兼职测试讲师,我们可以提供给您一份优厚的薪资,同时能在行业发展.企业培训.授课经验.出版专业著作等方 ...
- ConditionalOnProperty
配置Spring Boot通过@ConditionalOnProperty来控制Configuration是否生效 1.matchIfMissing属性:从application.properties ...
- qt5信息提示框QMessageBox用法
information QMessageBox::information(NULL, "Title", "Content", QMessageBox::Yes ...
- strncpy, strncpy_s
Defined in header <string.h> (1) char *strncpy( char *dest, const char *src, size_t co ...