manacher算法
Posted AC_Arthur
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了manacher算法相关的知识,希望对你有一定的参考价值。
ACM退役很久了, 不过仍然喜欢解决一些很酷的算法。
至此之后, 这里将会是一个纯净的算法讨论阵地, 和比赛无关, 但是希望能将算法的原理和做法讲解明白。
很后悔在做ACM的时候没有这么做。
博客推荐这个, 可以很快了解一下这个算法的做法:点击打开链接
那么我还是简单说一下。
我们从左往右扫描字符串枚举中点。算法维护了一个最右边的点, 这个是当前存在的回文串的最右边能到达的地方。
还维护了以每个点为中点的最长回文长度。我们分i和MaxRight的大小关系来进行判断, 上边博客说的很清楚了。我这里主要说一下时间复杂度的证明。
首先很明显, 这么做是肯定能求出最长回文的。但是时间复杂度为何是线性的呢。
首先如果i > MaxRight,那么在计算RL[i]的时候,这个MaxRight也会更新,也就是说,这时while循环等于用来移动了MaxRight,那么肯定是线性的。
那么如果i < MaxRight呢, 首先我们用与i对称位置的j的RL[j]避免计算了很大一部分重复的地方,如果此时更新RL[i]之后,RL[i]等于MaxRight了,那么情况和上面相同,这时while循环等于用来更新MaxRight, 但是如果RL[i]=RL[2*pos-i],说明其对称位置的j是一个很小的回文串,因为i所在部分和j所在部分是对称的,所以这时i也是不可能扩展的了(除非此时RL[i] == MaxRight,即RL[2*pos-i] == MaxRight-i)。
例题:点击打开链接
代码如下:
class Solution
public:
/*
* @param s: input string
* @return: the longest palindromic substring
*/
string longestPalindrome(string &s)
// Write your code here
static const int maxn = 2000 + 10;
static int RL[maxn];
string str = "";
str += '#';
for (int i = 0; i < s.size(); ++i)
str += s[i];
str += '#';
memset(RL, 0, sizeof(RL));
int MaxRight = 0;
int MaxLen = 0;
int pos = 0;
int ans = 0;
int StrLen = str.size();
for (int i = 0; i < StrLen; ++i)
if (i < MaxRight)
RL[i] = min(RL[2*pos-i], MaxRight - i);
else
RL[i] = 1;
while(i - RL[i] >= 0 && i + RL[i] < StrLen
&& str[i - RL[i]] == str[i + RL[i]])
RL[i] += 1;
if (RL[i]+i-1 > MaxRight)
MaxRight = RL[i]+i-1;
pos = i;
if (MaxLen < RL[i])
MaxLen = RL[i];
ans = i;
string res = "";
for (int i = ans - RL[ans] + 1; i < ans + RL[ans]; ++i)
if (str[i] != '#')
res += str[i];
return res;
;
以上是关于manacher算法的主要内容,如果未能解决你的问题,请参考以下文章
HDU - 5340 Three Palindromes(manacher算法)