马拉车算法是让你求出一个串儿中的最长回文字串的算法,他的时间复杂度均摊下来是o(n)的 ,他的主要难点在于如何构建出p数组,下面上代码,看着代码嘬着上面的注释会有更好的效果哦
代码:
马拉车算法是让你求出一个串儿中的最长回文字串的算法,他的时间复杂度均摊下来是o(n)的 ,他的主要难点在于如何构建出p数组,下面上代码,看着代码嘬着上面的注释会有更好的效果哦
代码:
#include <bits/stdc++.h>
int p[100000];//p[i] 表示的是你在第i点位中心的时候向左或向右(也就是半径!半径!) 的距离
int id,mx;//id 表示的是你现在所在的对称中心,mx表示的是在当前对称中心下你可以向右移动的最大位置在哪里
using namespace std;
int main()
{
string ch,sh;
sh = "$#";
//cin>>ch;
getline(cin,ch);
int len = ch.size();
for(int i = 0 ; i < len ;i++)
{
sh+=ch[i];
sh+="#";
}
int id = 0,mx = 0;
len = sh.size();
for(int i = 1 ; i < len ; i++)//需要注意的是当我们算到以i为回文串对称点的时候,那么以j(0<=j<i)为对称点的最长回文长度我们已经算出来了
{
p[i] = mx>i ? min(p[2*id-1],mx-i):1;
//_____mx`______j______id______i________mx____
// ______ _____ ①
// __|_______________ _____________|___
//对于mx>i的时候有两种情况,一种是i点关于id的对称点J点他的最长回文半径p[j]是小于mx-i的
//那么很显然这个时候 p[i] = p[j]的(如情况1,,因为我们知道以id为对称点的最长回文半径是大于i的,
//所以可以很清楚的知道,i和j是关于id对称的,那么i的对称长度其实就等于j的对称长度),第二种就是p[j]>mx-i的,那么对于这种情况我们
//可以肯定的是,在i到mx的位置我们可以肯定的是他们是回文的,(如情况②在|之前他们肯定都是回文)
//那么我们先把这部分给变成p[i]之后超过的部分我们就要去暴力匹配t[p[i] + i] 是不是 等于t[i-p[i]]
while(sh[p[i] + i] == sh[i-p[i]]) ++p[i];
if(p[i]+i > mx)
{
mx = i+p[i];
id = i;
}
}
int ans = 0 ;
for(int i = 0 ; i < len ; i ++)
{
ans = max(ans,p[i]-1);//解释一下这里为什么是p[i]-1,我们知道在我们变换过的串儿中所有的回文串都是奇数,而且p[i]中存的是
//以i位对称中点时候的半径!半径,那么总长其实就是2*p[i]-1(-1是因为对称中心多算了一次),之后我们可以发现
//在所有的回文字串儿中,分隔符一定比原来的字符多一个也就是多了p[i]个分隔符,那么还剩下来的原来的字符就是p[i]-1个
}
cout<<ans<<endl;
}