最长回文子串--马拉车(?)
每个回文串一定有一个中心,然而如果这个串长度是偶数,它的中心是空的,所以我们把长度为len的字符串变成长度2*len+1的字符串,每两个字符中间补上一个相同的字符。
用r[i]表示以i为中心的最长回文半径(如果字符两边不存在相同字符,r[i]=1)。记录下该半径对应的中心pos和半径达到的最远距离maxx,每当我们遍历一个i的时候,可以找到它对于pos对称的位置j,它的回文串半径一定大于等于j的回文串半径。如果j的回文串半径<2*pos-i+1,r[i]=r[j],反之,在maxx之外的距离可能也是i为中心的回文串的范围,所以我们一个个判断,更新maxx
因为maxx在每个位置最多被更新一次,所以复杂度O(n),看起来。。。很神奇?
#include<cstdio> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<iostream> using namespace std; char ss[1005]; char s[2010]; int r[2005];//最长回文半径 int main() { gets(ss+1); int len=strlen(ss+1); for(int i=1;i<=len;i++){ s[i*2]=ss[i]; s[i*2-1]='#'; } s[len*2+1]='#'; int pos=0,maxx=0; for(int i=1;i<=len*2+1;i++){ if(pos){ r[i]=min(maxx-i+1,r[pos*2-i]); while(i+r[i]<=len*2+1&&i-r[i]>0&&s[i+r[i]]==s[i-r[i]]) r[i]++; if(i+r[i]-1>maxx){ maxx=i+r[i]-1; pos=i; } } } return 0; }