数学之家
标题:
求回文串manacher算法
[打印本页]
作者:
低沉的游鱼
时间:
2014-6-17 22:25
标题:
求回文串manacher算法
本帖最后由 低沉的游鱼 于 2014-6-17 22:26 编辑
已被APIO题完虐,8分滚粗了。。于是我要下定决心好好学习。首先就学了一下manacher算法,T1要用到的算法
比如一个字符串abacaba,要求出里面所有的回文串。 如果回文串长度是奇数,就直接从中心向两边展开就行了。但如果是偶数呢?我们需要一个对这个字符串稍作变形。将这个字符串变为#a#b#a#c#a#b#a#。(#是一个辅助字符,要保证它在原串里不出现)。这样一来,原来长度是奇数的回文串长度还是奇数,长度为偶数的回文串就变成从其中一个#号展开。我们用p
表示在这个新的字符串str中,以str
为中心的最长回文串半径。这样一来,p
-1表示的以str
为中心的回文串在原串中的长度(很好证明,这里不多说)。
先贴一个完整的代码
#include<iostream>
#include<cstring>
using namespace std;
int manacher (char* s, int len)
{
int nlen = 2 * len + 3;
char* str = new char[nlen];
int i = 0;
int max = 0;
str[0] = ' ~';
str[1] = '#';
for (; i < len; i++)
{
str[i * 2 + 2] = s[i];
str[i * 2 + 3] = '#';
}
str[nlen - 1] = 0;
int* p = new int[nlen];
for (int i = 1; i < nlen; i++)
{
p[i] = 0;
}
int id = 0;
for (i = 1; i < nlen; i++)
{
if (max > i)
p[i] = min(p[2*id-i], max-i);
else
p[i] = 1;
while (str[i+p[i]] == str[i-p[i]])
p[i]++;
if (p[i]+i > max)
{
max = p[i] + i;
id = i;
}
}
int mx = 0;
for (i = 1; i < nlen; i++)
{
if (mx < p[i] - 1)
mx = p[i] - 1;
}
return mx;
}
int main()
{
char ch[100];
while (cin >> ch)
{
cout << manacher(ch, strlen(ch)) << endl;
}
return 0;
}
复制代码
这一句
if (max > i)
p
= min(p[2*id-i], max-i);
是整个算法中很重要的一个环节,利用了回文串的对称性,避免了许多不必要的计算。max表示的是之前的回文串匹配到的最远的位置,id保存的是这个回文串的i值。p[2*id-i]表示的就是i关于id对称的j的位置。但如果j的回文串长度较长,对称过来以后超出max的话,超出部分是还没有匹配的。因此,应该取的是两者之间较小值。
下图可能有助于理解
欢迎光临 数学之家 (http://www.2math.cn/)
Powered by Discuz! X3.1