首页 > 代码库 > hiho 第1周 最长回文子串

hiho 第1周 最长回文子串

题目链接:http://hihocoder.com/problemset/problem/1032

 

技术分享
#include <bits/stdc++.h>using namespace std;bool table[10000][10000] = {false};string longestPalindromeDP(string s){    int n = s.length();    int longestBegin = 0;    int maxLen = 1;    memset(table,0,sizeof(table));    for (int i = 0; i < n; i++)        table[i][i] = true;   //前期的初始化    for (int len = 2; len <= n; len++)    {        for (int i = 0; i < n-len+1; i++)        {            int j = i+len-1;            if (s[i] == s[j] && table[i+1][j-1])            {                table[i][j] = true;                longestBegin = i;                maxLen = len;            }        }    }    return s.substr(longestBegin, maxLen);}int main(){    int t;    cin>>t;    while(t--)    {        string str;        cin>>str;        string ans = longestPalindromeDP(str);        cout<<ans.length()<<endl;    }    return 0;}
View Code
技术分享
#include <bits/stdc++.h>using namespace std;const int maxn = 1000008;char instr[maxn],str[maxn*2];int rad[maxn*2];int Manacher(){    int i,j,maxx;    int n = strlen(instr);    memset(str,#,sizeof(str));    for(i=0;i<n;i++)        str[(i+1)<<1] = instr[i];    n = (n+1)<<1;    str[n] = $;    int maxRad;    maxRad = j = maxx = 0;    for(i = 0;i<n;i++)    {        if(i<maxx)            rad[i] = min(rad[2*j-i],maxx-i);        else rad[i] = 1;        while(str[i-rad[i]]==str[i+rad[i]])            rad[i] ++;        if(maxRad<rad[i])            maxRad = rad[i];        if(rad[i]+i>maxx)        {            j = i;            maxx = rad[i] + i;        }    }    return maxRad;}int main(){    int t;    scanf("%d",&t);    while(t--)    {        scanf("%s",instr);        printf("%d\n",Manacher()-1);    }    return 0;}
View Code

先是用DP写了一下,

DP方程,就是用一个二维数组标记table[i][j] 字符串i,到j是否构成回文串,然后枚举最大长度len,

要是两端相等,并且,可以扩展,那么longestBegin = i,maxlen = len;时间复杂度还是O(n^2),并且数组都开不了。

 

然后就是Manacher算法:

参考:http://www.cnblogs.com/lv-2012/archive/2012/11/15/2772268.html

先扩充为两倍的字符串,rad[i]表示新的字符串第I个位置可以向左向右匹配的最大距离。求出这个rad数组,有一个结论,rad - 1就是原串对应的位置能匹配的最大长度。

那么怎么求rad数组:

求rad[i] 的时候,如果知道rad 前面的值,还有前面有个位置 ID,能够扩充的最大距离是max,

那么rad = min(rad[2*id-i],max-i);

原因:

当 mx - i > P[j] 的时候,以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中,由于 i 和 j 对称,
以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中,所以必有 P[i] = P[j],见下图。
   技术分享
  
   当 P[j] > mx - i 的时候,以S[j]为中心的回文子串不完全包含于以S[id]为中心的回文子串中,但是基于
对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以S[i]为中心的回文子串,其向右至少会
扩张到mx的位置,也就是说 P[i] >= mx - i。至于mx之后的部分是否对称,就只能老老实实去匹配了。
  技术分享

 

hiho 第1周 最长回文子串