hdu 3068 最长回文 (Manacher算法求最长回文串)
参考博客:Manacher算法--O(n)回文子串算法 - xuanflyer - 博客频道 - CSDN.NET
从队友那里听来的一个算法,O(N)求得每个中心延伸的回文长度。这个算法好像比较偏门,不过还是稍微掌握一下会比较好。
其实,我的理解就是,记录当前知道找到的最长的回文串的中心以及向右延伸后的最右端点位置。然后其中找最长回文串的操作其实还是暴力的,只不过这样记录两个位置以及覆盖了区间以后,下次我们要找的最长回文串的时候就可以借助这个已知信息减少大量的冗余查找。至于怎么证明这个剪枝可以使算法达到O(N)的复杂度,还是找资料比较好。
用hdu 3068这题测试,340ms通过:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <ctime> 6 7 using namespace std; 8 9 const int N = 111111; 10 char str[N], nstr[N << 1]; 11 int p[N << 1]; 12 13 int manacher(char *s) { 14 int id = 0, lf = 0, len = strlen(s), mx = 1; 15 p[0] = 1; 16 for (int i = 1; i < len; i++) { 17 if (lf > i) p[i] = min(p[(id << 1) - i], lf - i); 18 else p[i] = 1; 19 while (s[i + p[i]] && s[i + p[i]] == s[i - p[i]]) p[i]++; 20 if (lf < i + p[i] - 1) lf = i + p[i] - 1, id = i; 21 mx = max(p[i], mx); 22 } 23 return mx - 1; 24 } 25 26 int main() { 27 while (~scanf("%s", str)) { 28 char *p = str, *q = nstr; 29 while (true) { 30 *(q++) = '~', *(q++) = *p; 31 if (!*p) break; 32 p++; 33 } 34 //cout << nstr << endl; 35 cout << manacher(nstr) << endl; 36 } 37 return 0; 38 }
——written by Lyon