2015-07-21 10:48:31
【学习传送门】
总结:线性求以每个位置为中心的最长回文串O(n)算法 get 。
(1)在相邻位置间插入特殊字符 / 数字。从而将所有回文串的长度转化为奇数。
(2)用类似DP的方法线性求出每个点的 P[] 函数,P[i]
void Manacher(){ int top = 2 * n + 1; int tmax = 0,id = 0; for(int i = 1; i <= top; ++i){ if(tmax > i){ P[i] = min(P[2 * id - i],tmax - i); } else{ P[i] = 1; } while(tc[i - P[i]] == tc[i + P[i]]){ P[i]++; } if(i + P[i] > tmax){ tmax = i + P[i]; id = i; } } }
经典题目:
(1)HDU 3068 求最长回文串(如果字符串从 1 位置开始的话,注意把 str[0] 赋值为另一个特殊字符,比如 ‘?’。
#include <cstdio> #include <ctime> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB push_back typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const int MAXN = 110010 * 2; char s[MAXN],ts[MAXN]; int P[MAXN]; int main(){ while(scanf("%s",ts + 1) != EOF){ int len = strlen(ts + 1); for(int i = 1; i <= len; ++i){ s[i * 2 - 1] = '#'; s[i * 2] = ts[i]; } s[0] = '?'; s[len * 2 + 1] = '#'; s[len * 2 + 2] = '\0'; int tmax = 0,id = 0; len = len * 2 + 1; int ans = 0; for(int i = 1; i <= len; ++i){ if(tmax > i){ P[i] = min(P[2 * id - i],tmax - i); } else{ P[i] = 1; } while(s[i - P[i]] == s[i + P[i]]){ P[i]++; } if(i + P[i] > tmax){ tmax = i + P[i]; id = i; } ans = max(ans,P[i]); } printf("%d\n",ans - 1); } return 0; }