您的位置:首页 > 其它

hiho第一周——最长回文子串

2015-06-09 20:07 302 查看

hiho第一周——最长回文子串

题目链接:http://hihocoder.com/contest/hiho1/problem/1

资料来源于网络:http://www.felix021.com/blog/read.php?2040

关键点

Manacher算法的关键点就在这里了:如果max_right> i,那么P[i] >= MIN(P[2 * ind - i], max_right- i)

上图方便理解:

当 mx - i > P[j] 的时候,以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中,由于 i 和 j 对称,以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中,所以必有 P[i] = P[j],见下图。



当 P[j] >= mx - i 的时候,以S[j]为中心的回文子串不一定完全包含于以S[id]为中心的回文子串中,但是基于对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以S[i]为中心的回文子串,其向右至少会扩张到mx的位置,也就是说 P[i] >= mx - i。至于mx之后的部分是否对称,就只能老老实实去匹配了。



p.s.数组 P[i] 来记录以字符S[i]为中心的最长回文子串向左/右扩张的长度(包括S[i])

可执行代码

#include <iostream>
#include <string>
#include <fstream>
#include <cmath>
#include <vector>
using namespace std;

int longest_panlin(string s);

int main()
{
fstream cin("input.txt");
int N;
cin>>N;
while(N>0)
{
string s;
cin>>s;
int result;
result=longest_panlin(s);
cout<<result<<endl;
N--;
}
return 0;
}

int longest_panlin(string s)
{
//预处理,因为manacher算法对于奇数个字符的字符串,代码可以大大简化(但是这加大了空间复杂度)
string str="#";
for(int i=0;i<s.size();i++){str+=s[i];str+='#';}
//记录最长回文子串的长度。比如以c为中心的#a#c#a#,它的result为4,最终函数应该返回3
int result=0;
//右端最右的回文子串,它的中心位置
int ind=0;
//右端最右的回文子串,它的右端位置
int max_right=0;
int n=str.size();
//动态数组,记录以下标为中心位置,它的最长回文字串的右边长度(包括中心点)
int *p=new int
;
p[0]=1;

for(int i=1;i<n;i++)
{
//该算法的核心思想,具体请看图
if(max_right>i)
p[i]=min(p[2*ind-i],max_right-i);
else
p[i]=1;
//在不越左边界,不越右边界的情况下,获取该中心的回文子串最大的长度
for(;i>=p[i]&&i+p[i]<n&&str[i+p[i]]==str[i-p[i]];)
p[i]++;
//记录结果
if(p[i]>result)result=p[i];
//不断获得右端最右的回文子串(这是为什么呢?是跟时间复杂度有关吗?)
if(p[i]+i>max_right)
{
max_right=p[i]+i;
ind=i;
}
}
delete p;
return result-1;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息