#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
using namespace std;
char c[2000010];
void Insert(string s){
c[0]='@';
for(int j=0; j<s.length(); j++){
c[2*(j+1)]= '@';
c[2*j+1]=s[j];
}
}
int min(int a, int b){
return a>b?b:a;
}
int main()
{
int n;
int mx;
int p;
int max;
string s;
vector<int> v;
cin>>n;
for(int j=0; j<n; j++){
cin>>s;
Insert(s);
max=0;
mx=0;
p=0;
v.clear();
int l=2*s.length()+1;
for(int i=0; i<l; i++){
//cout<<max<<endl;
if(mx>i){
v.push_back(min(mx-i, v[p*2-i]));
}else{
v.push_back(1);
}
while(c[i+v[i]]==c[i-v[i]] && (i+v[i])<l && (i-v[i])>=0) v[i]++;
if((v[i]+i)>mx) {
mx=v[i]+i;
p=i;
}
if(v[i]>max) max=v[i];
}
cout<<max-1<<endl;
}
return 0;
}
hihoCoder的1032道题的解题代码
附上最易理解的
算法讲解讲解
http://m.blog.csdn.net/article/details?id=42061017
以及我理解的Manacher算法:
该算法的思想是从中心向两边探索回文,并标记之前探索的回文右边最远的字符的下标
1)如果是这种情况:
0 1 2 3 4 5 6 7 8 9 10
c b c d c b c c e c a
比如现在我要探索的是b(下标5),之前探索的以d(下标3)文中心的最长回文是c b c d c b c,右边最远字符是c(下标6),以d为中心最有两边是对称的,b(下标5)的对称点是b(下标1),右边最远字符c(下标6)关于d的对称点是下标0的字符c,则b(下标1)到c(下标0)这部分的对应字符是b(下标5)到c(下标0),这部分字符前面已经探索过了,可以跳过匹配过的,从c(下标7)开始探索,因为这部分是未探索过的。
2)如果是这种情况:
0 1 2 3 4 5 6 7 8 9 10
a b c d c b a c e c a
比如现在我要探索的是c(下标7),之前探索的以d(下标3)文中心的最长回文是c b c d c b c,右边最远字符是c(下标6),c(下标7)是一个新的字符,自己本身都没有匹配过,因此只能老老实实的一个一个的两边匹配了。
以上是我的理解。