线性复杂度找回文串?Manacher马拉车----字符串算法
Manacher
O(n)O(n)O(n) 求最长回文串。
回文串分奇数串和偶数串,我们在字符前后加入‘#’,都转化为奇数串,方便处理。如 acaacaaca 转化为 XaXcXaXXaXcXaXXaXcXaX。
设 pip_ipi 表示以 iii 为对称轴,能扩展的最长长度。设当前扩展到的最右端为 mxmxmx,扩展到 mxmxmx 的对称轴是id。
我们依次往后看,若当前看到的位置为 iii ,若 i≤mxi\leq mxi≤mx,那 iii 关于 ididid 对称的 jjj,他们两个是对称全等的。
此时有两种情况,iii 完全用 jjj 的回文串,此时要求 j−p[j]j-p[j]j−p[j] 不超过以 ididid 为中心的左端点。若超过,答案则为 mx−imx-imx−i (因为 p[j]p[j]p[j] 那里要是超了 mxmxmx,肯定只能取到这个 mxmxmx 的位置啦)。
若在边界上或是≥mx\geq mx≥mx ,则可以继续扩展,暴力扩展即可。
因为每次暴力扩展都是线性向右的,所以复杂度为线性的。
#include<bits/stdc++.h>
using namespace std;
const int N=22000000+20;
string a,s;
int len;
int p[N];
int main(){cin>>s;for(int i=0;i<s.size();++i){a+='#';a+=s[i];} a+='#';len=a.size();int mx=0,id=0;int ans=0;for(int i=0;i<len;++i){if(i<mx) p[i]=min(p[2*id-i],mx-i+1);else p[i]=1;while(i-p[i]>=0&&i+p[i]<len&&a[i-p[i]]==a[i+p[i]]) p[i]++; //暴力扩展if(p[i]+i>mx) mx=p[i]+i-1,id=i;ans=max(ans,p[i]-1);}printf("%d\n",ans);return 0;
}