马拉车
该算法解决一长串字符的最大长度回文字符串(当然他的用处不仅局限于此)
普通解法 时间复杂度o(n*n) 马拉车算法 o(n)。
原串S: abbbab
变化后的 新串 T
T =@ # a # b # a # a # b # a #
P = 0 0 1 0 3 0 1 6 1 0 3 0 1 0 //p数组
//为什么要变化S,成新串,后续解释
发现了点端倪了吧 怎么会有p数组的值也是怎么对称呢。
1 0 3 0 1 6 1 0 3 0 1 (以后补,睡觉了)
链接: link.
这位大牛的代码解释原理的很好
题解思路来自于此。
马拉车原理:
主要是因为回文有对称关系,
就好比我已经知道一个回文串以中心点左边的每个点回文串长度
(可能说起来比较拗口,其实就是下文中的p数组)
#include<iostream>
#include<cstring>
using namespace std;
#define maxn 100005
char s[maxn],news[2*maxn];
int p[2*maxn];
int len;
void bian(){ //长度变两倍
news[0] = '@';
news[1] = '#';
for(int i=1;i<=len;i++)
{ news[2*i] = s[i];
news[2*i+1] = '#';
}
//cout<<news<<endl;
for(int i=1;i<=2*len+1;i++){
cout<<news[i]<<" ";
}
cout<<endl;
return ;
}
void Pzu(){ //p数组
int lens = 2*len +1;
int id,mx = 0; // mx = id + p[id] 懂的都懂
// id 回文中点 mx 子串回文末端
for(int i=1;i<=lens;i++){
if(i<=mx)
p[i] = min(p[2*id-i],mx-i);
//若是mx-i 说明回文p[2*id-i]已经超出mx的范围。
// 在以id 为 中心 半径为p[id].
else
p[i] =1 ;
while(news[p[i]+i]==news[i-p[i]]) p[i]++;
if(i+p[i]>mx)
mx=i+p[i],id =i;
}
for(int i=1;i<=lens;i++)
cout<<p[i]<<" "; //马拉车p数组,最大回文串长度pmax-1
return ;
}
int main (){
scanf("%s",s+1);
len = strlen(s+1);//字符串长度
bian();
Pzu();
}
//样例:babcbabcbaccba
//最大回文数为 9