回文串

最长回文子串Manacher算法

[亡魂溺海] 提交于 2019-12-04 20:17:48
回文串是这样的abba,ababa,就是把这个串翻转过来和原串是一样的, 最长回文子串,就是在一个长串中找到一个 子串,这个子串是 长串中的最长回文子串 简单的做法是 指定前后两个指针,判断这两个指针之间的字符串是否是回文串,并记录最大值 有一个算法是来计算最长回文子串的叫做Manacher,在网上找了半天有点没看懂,最后自己在纸上模拟一下才弄懂,说一下自己的思路 首先将字符串S用‘#’分隔,以"waawabawab" 为例子 原串S变成 S: # w # a # a # w # a # b # a # w # a # b # 然后我们用一个p数组,p[i]记录 以str[i]为中间字符的回文串向右能匹配的长度 我们人工计算一下可以看到结果是这样的 S: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 i: # w # a # a # w # a # b # a # w # a # b # p[i]: 1 2 1 2 5 2 1 4 1 2 1 8 1 2 1 6 1 2 1 2 1 可以看到 当i=4时,当前字符是‘#’,以它为中间字符能构成的最长回文串是#w#a(#)a#w# ,括号内为当前字符,所以结果是5,但是这个值用程序怎么做出呢,还要以它为中间字符向左右遍历查找吗,当然不是。。。 我们引入两个变量id和mx,

字符串的最长回文子串--manacher算法

你。 提交于 2019-12-04 20:17:33
预备知识: 字符串概念 回文子串概念 朴素算法: 通常我们熟知的求解字符串的最长回文字串的方法有以下两种算法: 1、O(n^2)枚举子串的左右两个端点->O(n)判断该子串是否为回文串:总复杂度O(n^3); 2、O(n)枚举每一个回文子串的中点(偶数长度类似,不做讨论)->O(n)向两端拓展:总复杂度O(n^2)。 然而在一般的算法竞赛中,O(n^2)复杂度求回文子串的算法是无法接受的,下面介绍一种在线性时间内求字符串的最长回文子串的算法--manacher算法。 manacher算法: 如果将上述算法2视为算法1的优化版本,那么manacher算法可视为算法2的优化版本。下面先分析算法2的不足之处。 对于算法2我们会枚举每一个位置的中点,每次都从枚举点开始向两端拓展。比如下图中枚举了7作为中点,假设其两端最远拓展的长度为6,即字符串[1~13]为一个回文子串(并且13为当前向右拓展的最远距离)。当我们再枚举11作为中点时,我们会依次比较:(10,12)->(9,13)->......,这样的复杂度就是O(n^2)。然而实际上我们还需要对7为中点的子串进行这样的枚举吗? 其实是不需要的。 因为我们已经知道了[1~13]为一个回文子串了,也就是说子串[1~7]与[7~13]一样(下图红框所示)。那么子串[9~13]当然与对称位置的子串[1,5]一样(下图蓝框所示)。更本质一点就是

Manacher算法--求最长回文子串

旧时模样 提交于 2019-12-04 20:17:12
回文和回文子串 回文串:顺着读和倒着读都一样的字符串; 回文子串:给定字符串string,若str同时满足以下两个条件:1)str是string的子串;2)str是回文串;那么str就是string的回文子串; 引出问题 要求求出上面string中最长的那个回文子串; 解决方案 方案一:枚举中心位置,对奇数位串和偶数位串分开处理; int AllAlgorithms::longestPalindrome(const char *s, int n){ int max,j; if (0 == s || n < 1) { return 0; } max = 0; for (int i = 0; i < n ; ++ i) {//i为回文串的中心 for ( j = 0; ((i - j) >= 0) && ((i+j) < n); ++j) {//如果回文串的长度是奇数 if (s[i-j] != s[i+j]) { break; } if ((j * 2 + 1) > max) { max = 2*j + 1; } } for (j = 0; ((i-j) >= 0) && ((i+j+1) < n); ++j) {//如果回文串的长度是偶数 if (s[i-j] != s[i+j+1]) { break; } if ((j * 2 + 2) > max) { max = 2*j +

Hihocoder #1032 : 最长回文子串 (Manacher算法)

放肆的年华 提交于 2019-12-04 20:16:44
#1032 : 最长回文子串 时间限制: 1000ms 单点时限: 1000ms 内存限制: 64MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进。 这一天,他们遇到了一连串的字符串,于是小 Hi 就向小 Ho 提出了那个经典的问题:“小 Ho ,你能不能分别 在这些字符串中找到它们每一个的最长回文子串 呢?” 小Ho奇怪的问道:“什么叫做最长回文子串呢?” 小Hi回答道: “一个字符串中连续的一段就是这个字符串的子串,而回文串指的是12421这种从前往后读和从后往前读一模一样的字符串,所以最长回文子串的意思就是这个字符串中最长的身为回文串的子串啦~” 小Ho道:“原来如此!那么我该怎么得到这些字符串呢?我又应该怎么告诉你我所计算出的最长回文子串呢? 小Hi笑着说道:“这个很容易啦,你只需要写一个程序, 先从标准输入读取一个整数N (N<=30) ,代表我给你的字符串的个数,然后接下来的就是我要给你的那N个字符串(字符串长度<=10^6)啦。 而你要告诉我你的答案的话, 只要将你计算出的最长回文子串的长度按照我给你的顺序依次输出到标准输出就可以了! 你看这就是一个例子。” 提示一 提示二 提示三 提示四 样例输入 3 abababa aaaabaa acacdas 样例输出 7 5 3 题解:

最长回文子串,Manacher算法

烈酒焚心 提交于 2019-12-04 20:16:31
回文串就是一个字符串从左到右和从右到左是一样的,或者说他是关于中心对称的。 如何找出一个字符串中最长的回文子串呢(假设只有唯一的最长回文子串)?Manacher算法给出了O(n),的解法。 字符串的个数,偶数与奇数时判断有不同,为了简化,给每一个字符加一个特定的字符,这样就可以保证字符串始终是基数,如:#a#, #a#a# 其次需要一个idx,一个max和一个数组p,mx记录了当前所有回文串中最右边的位置,id就是这个回文串的中心位置,p[i]记录了一str[i]为中心的回文串的半边长。如下所示: # a # b # c # c # d # p[i] 1 2 1 2 1 2 3 2 1 2 1 当访问到b的时候,mx=4, id=3。求得p,也就求得了结果。 在求p[i]时,p[i]的初始化有两种情况: 结合参考图来理解 mx <= i,p[i] = 1; mx > i, p[i] = min(p[2*id - i], mx - i + 1) 上面我们讲的是p[i]的初始化,而不是最终的结果,j是i以id为中心的对称点,如果p[j]是在mx - i范围内的,取p[j],否则去mx-i,否则=mx-i+1. 之后在以i为中心,p[i]为边长想两端扩展,判断回文。在判断的时候需要注意不要越界,因为有结束符‘\0'存在,所以只需考虑起点就行。 string Manacher(string

最大回文子串manacher算法python

亡梦爱人 提交于 2019-12-04 20:16:07
关于最大回文子串问题,有两种处理方法: 1.以每个字符为中心,向两边寻找回文子串,遍历整个数组后,返回最长的。 该方法时间复杂度较大为o(n^2) 2.一个中等难度的动态规划算法:马拉车 step1:给每个字符左右都加上特殊字符比如'#',处理后,能使字符串s长度为奇 step2:现在的问题变成如何高效求得RL数组 定义:RL:是一个回文半径数组 RL[i]:以第i个字符为对称轴的回文半径 maxRight:当前访问到的所有回文串中最右边的字符位置 Pos:maxRight对应回文串的对称轴所在位置 i:第i个字符 j:i关于pos的对称点 (1):i在maxright右边:就是说以i为对称轴的回文串还没被访问。 这时,以i为中心向两边扩展,当达到边界or字符不相等时停止。 (2):i在maxright左边:扫到了一部分以i为对称轴的子串。 这时,令以i为对称轴的回文半径RL【i】=min(RL[j],maxright-i) 然后再以i为中心向两边扩展,直到左!=右且到达边界 最后更新maxright=max(maxright,RL[i]+i-1)且若maxright变,Pos会变为Pos=i 很抽象,上代码: # -*- coding:utf-8 -*- #@author:xinxinzhang def manacher(s): s='#'+'#'.join(s)+'#'

最长回文子串——Manacher 算法

一个人想着一个人 提交于 2019-12-04 20:15:50
原文网址: https://segmentfault.com/a/1190000003914228 0. 问题定义 最长回文子串问题:给定一个字符串,求它的最长回文子串长度。 如果一个字符串正着读和反着读是一样的,那它就是回文串。下面是一些回文串的实例: 12321 a aba abba aaaa tattarrattat(牛津英语词典中最长的回文单词) 1. Brute-force 解法 对于最长回文子串问题,最简单粗暴的办法是:找到字符串的所有子串,遍历每一个子串以验证它们是否为回文串。一个子串由子串的起点和终点确定,因此对于一个长度为n的字符串,共有n^2个子串。这些子串的平均长度大约是n/2,因此这个解法的时间复杂度是O(n^3)。 2. 改进的方法 显然所有的回文串都是对称的。长度为奇数回文串以最中间字符的位置为对称轴左右对称,而长度为偶数的回文串的对称轴在中间两个字符之间的空隙。可否利用这种对称性来提高算法效率呢?答案是肯定的。我们知道整个字符串中的所有字符,以及字符间的空隙,都可能是某个回文子串的对称轴位置。可以遍历这些位置,在每个位置上同时向左和向右扩展,直到左右两边的字符不同,或者达到边界。对于一个长度为n的字符串,这样的位置一共有n+n-1=2n-1个,在每个位置上平均大约要进行n/4次字符比较,于是此算法的时间复杂度是O(n^2)。 3. Manacher

最长回文子串 manacher算法

感情迁移 提交于 2019-12-04 20:15:00
求最长回文子串比较有名的一种算法,复杂度是O(n)的,(不要问我为什么是O(n))。 思路 :尽量利用到之前遍历得到的回文信息。 表示以i为中心,最长的回文子串的半径有多长,并保存当前的回文子串往右延伸,最长能延伸到哪,即p[i]+i的最大值,存为right,其回文子串的中心点存为index。 考虑当下标为i时,要求p[i]。有几种情况: 1. 当i > right时,超出了之前得到的信息的范围,只能从i开始向两边遍历,求最长的回文范围了; 2. 当i < right时,说明现在还在之前遍历过的范围内,那么就把之前的信息利用起来。 p[i]最大可能为多大? 考虑一下以index为对称中心的i ‘,如果i ’ - p[i ‘] > left,也就是说i ‘为中心的最长回文子串完全被left-right包含,那么因为是对称的,所以i为中心的最长回文串也就是p[i ‘];如果i ’ - p[i ‘] < left,也就是说i ’ 为中心的最长回文子串超出了left-right的范围,那么以i为中心的回文串能超出right的范围吗。答案是不能,看一下图就知道如果超出了,两边又是对称的,那么left-right就延长了,而left-right已经是以i为中心的最长回文子串了,所以p[i] = min{p[i ‘], right - i}。 上面的方法,回文串必须是奇数长的,因为有中心点嘛

最长回文子串-Manacher算法(详解)

北城以北 提交于 2019-12-04 20:14:39
定义: 回文串 :一个字符串, 逆置之后,与原串相同; 回文子串 : 一个字符串的子串( 连续 ),是回文串.则该子串为整个字符串的一个回文子串. 最长回文子串:一个字符串中最长的回文子串. 求最长回文子串最容易 想 的 方法1(dp): 先将串逆置,再与原串求最长公共子序列(LCS)(o(n^2)), //时间O(n^2) 空间O(f(n^2)); 方法2(纯暴力): 两重循环枚举起点终点(所有子串)(o(n^2)),如果是回文串,返回长度,不是返回0(o(n)),寻找最大长度.//时间 O(n^3); 稍微提升一下, 方法3(中心扩展): 枚举对称中心, 向两边扩展,遇边界,或不同,停止扩展,继续下一个对称中心,之后找最大//O(n^2); 方法4(dp): 暴力改进: 辅助数组记录从i到j是否回文 P(i,j)= P(i+1,j-1)(如果S[i] = S[j])。类动规方程。 P(i,i)= 1,P(i,i+1)= if(S[i]= S[i+1]) 个人感觉没LCS好写,好想. 下面进入正题,传说 Manacher 能 O(n), 你信吗? 反正我不信. 我看了下, 别人的博客上来就说要分奇数偶数,然后加’#’,然后谁小于等于谁,然后贴代码. 所以决定认真写下本篇博客.解除疑惑. 想写代码,首先要懂道理,看别人代码,花了好长时间看懂了,昂,是这么一回事,等让自己写原题时

解决最长回文子串问题——Manacher算法

半城伤御伤魂 提交于 2019-12-04 20:14:24
问题描述: 输入一个字符串,求出其中最大的回文子串。子串的含义是:在原串中连续出现的字符串片段。回文的含义是:正着遍历和倒着遍历得到的序列相同,如madam,lol,oppo,zz。 计算字符串的最长回文字串最简单的算法就是枚举该字符串的每一个子串,并且判断这个子串是否为回文串,这个算法的时间复杂度为O(n^3)的,而稍微优化的一个算法是枚举回文串的中点,这里要分为两种情况,一种是回文串长度是奇数的情况,另一种是回文串长度是偶数的情况,枚举中点再判断是否是回文串,这样能把算法的时间复杂度降为O(n^2),但数据大的话,依然让人无法满意,这时Manacher(谐音马拉车)算法横空出世,在线性时间复杂度内求出一个字符串的最长回文字串,达到了理论上的下界。但同时,此算法的应用也十分狭窄,只能解决此类问题。 算法要点前导 :刚才在朴素的O(n^2)蛮力方法中要考虑串的长度问题为奇数还是偶数,但马拉车算法使用了一个巧妙的方法解决了这个问题, 在原序列中加上分隔符,使序列原本无论奇偶都变了奇数长度[i + (i+1)一定为奇数]。 比如oppovivo这个串,我们在每两个字符之间加上一个特殊符号(通常为串中不曾出现的符号),通常用#来充当,这样变为了#o#p#p#o#v#i#v#o#,原本8个元素现在变为17个。 此处许多博主使用了一个优化方法:可在在首尾加上两个 不同 的特殊字符