解决的问题?:
Manacher :
一个将时间复杂度优化到O(n)的算法;
暴力算法,但不是纯暴力,即按照做过的事情不再去做来优化;
第一步:改变字符串
我们知道,一个回文串要么是奇数的串:aba ,, 要么是偶数的串:abba;
可以看出,一个回文串有一个对称轴;
对于奇数串aba来说,对称轴就是b;
而对于偶数串abba来说,对称轴在abba的两个b之间,可我们又没有保存这两个b之间的那个位置;怎么办呢:
于是我们将读入的字符串进行如下处理:
s=aba 那么 str=$ #a#b#a#
s=abba 那么 str=$ #a#b#b#a#
在每两个单词间插入一个#号,$是一个边界;
第二步,理解做过的事情不再做:
我们要维护几个信息:
id表示上一次操作的点
mx表示上一次操作的回文操作的最右端
len[i]表示第i个位置为对称轴的最长回文子串的右半边
Code:
#include <bits/stdc++.h>
using namespace std;
#define maxn 11000010
char s[maxn],str[maxn<<1];
int len[maxn<<1],len1,len2;
inline void clean_() {
memset(str,0,sizeof(str));
}
inline void init_() {
int k=0;
str[k++]='$';
for(int i=0;i<len1;i++) {
str[k++]='#';
str[k++]=s[i];
}
str[k++]='#';
len2=k;
}
inline int Manacher_() {
len[0]=0;
int sum=0,mx=0,id=0;
for(int i=1;i<len2;i++) {
if(i<mx) len[i]=min(mx-i,len[2*id-i]);
else len[i]=1;
while(str[i-len[i]]==str[i+len[i]]) len[i]++;
if(len[i]+i>mx) {
mx=len[i]+i;
id=i;
sum=max(sum,len[i]);
}
}
return (sum-1);
}
int main( ) {
clean_();
scanf("%s",s);
len1=strlen(s);
init_();
printf("%d",Manacher_());
return 0;
}