转载之http://blog.csdn.net/ggggiqnypgjg/article/details/6645824地址
之前自己做过这道题目,不过算法复杂度是O(n^2)的时间复杂度和空间复杂度的
后来http://hihocoder.com/contest/hiho1/rank 这个有比赛,写了个O(n^2)的
一致TLE,看到discuss才发现有O(N)算法,真的是膜拜
代码来源 http://acm.hust.edu.cn:8080/judge/problem/viewSource.action?id=140283
- /*****************************************
- *
- * 2011,UESTC_ACM
- * 回文串
- * By a180285
- * O(n) 算法
- *****************************************/
- # include <math.h>
- # include <stdio.h>
- # include <string.h>
- # include <stdlib.h>
- # include <algorithm>
- # include <iostream>
- # include <string>
- # include <queue>
- # include <stack>
- # include <map>
- # include <set>
- # include <vector>
- # include <cstring>
- # include <list>
- # include <ctime>
- # include <sstream>
- # define For(i,a) for((i)=0;i<(a);(i)++)
- # define MAX(x,y) ((x)>(y)? (x):(y))
- # define MIN(x,y) ((x)<(y)? (x):(y))
- # define sz(a) (sizeof(a))
- # define MEM(a) (memset((a),0,sizeof(a)))
- # define MEME(a) (memset((a),-1,sizeof(a)))
- # define MEMX(a) (memset((a),0x7f,sizeof(a)))
- # define pb(a) push_back(a)
- using namespace std;
- typedef long long ll ;
- typedef unsigned long long ull ;
- typedef unsigned int uint ;
- typedef unsigned char uchar ;
- template<class T> inline void checkmin(T &a,T b){if(a>b) a=b;}
- template<class T> inline void checkmax(T &a,T b){if(a<b) a=b;}
- const int oo=1<<30 ;
- const double eps=1e-7 ;
- const int N=1 ;
- const int M=1100110*2 ;
- const ll P=10000000097ll ;
- char str[M];//start from index 1
- int p[M];
- char s[M];
- int n;
- void kp()
- {
- int i;
- int mx = 0;
- int id;
- for(i=1; i<n; i++)
- {
- if( mx > i )
- p[i] = MIN( p[2*id-i], p[id]+id-i );
- else
- p[i] = 1;
- for(; str[i+p[i]] == str[i-p[i]]; p[i]++)
- ;
- if( p[i] + i > mx )
- {
- mx = p[i] + i;
- id = i;
- }
- }
- }
- void pre()
- {
- int i,j,k;
- n = strlen(s);
- str[0] = '$';
- str[1] = '#';
- For(i, n)
- {
- str[i*2 + 2] = s[i];
- str[i*2 + 3] = '#';
- }
- n = n*2 + 2;
- str[n] = 0;
- }
- void pt()
- {
- int i;
- int ans = 0;
- // For(i, n)
- // printf("%c", str[i]);
- // puts("");
- // For(i, n)
- // printf("%d", p[i]);
- // puts("");
- For(i, n)
- checkmax(ans, p[i]);
- printf("%d\n", ans-1);
- }
- int main()
- {
- int n = 0;
- cin>> n;
- while( n--){
- cin>>s;
- pre();
- kp();
- pt();
- }
- return 0;
- }
具体做法可以参考链接;
对于一个字符串数组,我们将其插入一些字符,例如“#”
例如字符 a b c d d f g g
插入后 #a#b#c#d#d#f#g#g#
p[id] 12121212
定义数组 p[],对于插入后的字符串数组我们为chs[]吧
p[id] 表示位置id上为中心的最长回文串向右边可以扩展p[id]个位置,显然,可知
p[id] - 1 就是以id为中心的最长回文串的长度了
定义一个id,当前所知道能最右边扩展的位置的中心点;mx,该id
可以向右扩展mx位
那么只要求出p[] 这个数组,就可以知道最长回文串的长度了
上面的式子是根据回文串的对称性做的,理解上不难
因为是从低坐标向高坐标遍历的,id总是小于等于i
对于 p[i], 如果当前mx的值是大于i,所以i是位于以id为中心的回文串中的
也就是说以id为中心,可以找到i的对称,称其为j,(j 总是小于i)
因为p[j]是已知的,只需求出j 的值即可 j = 2 * id - i,这是第一种情况
第二种情况是在当mx - i 也就说 i在以id为中心的回文串中的长度,小于p[j]的长度,看上图,第二行的
右边的长方体的长度是大于mx的,(左右两边是对称的),由于mx之外值我们还没有比较,所以
当前只能取两者中较小的。
算法的构思十分巧妙,再次膜拜