hiho 第1周 最长回文子串

Posted 树的种子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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周 最长回文子串的主要内容,如果未能解决你的问题,请参考以下文章

《算法竞赛入门经典》3.3最长回文子串

精选力扣500题 第30题 LeetCode 5. 最长回文子串c++ / java 详细题解

LeetCode 第516题:最长回文子序列

LeetCode 第5题 最长回文子串

华为机试题 HJ85最长回文子串

华为机试题 HJ85最长回文子串