【leetcode】最长回文子串

问题描述:

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba"也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

解题思路:参考这篇文章加深了对动态规划算法的了解和使用:https://www.cnblogs.com/coderJiebao/p/Algorithmofnotes30.html

但是对广为流传的Manacher算法还是不理解,估计需要踩坑才会努力去了解。

因此我使用的是动态规划的方法来解决。

1、维护一个dp矩阵,来表示对应的子串是否是回文串。

2、首先计算长度为1和2的子串是否是回文串,然后再扩展为3-len长度的子串是否是回文串,因为子串的长度是递增的,因此每次保存的回文串的开始和结束下标:begin\end,最后遍历完成的下标也就是最长回文串的下标了。

char* longestPalindrome(char* s) {
    if(s==NULL || strlen(s)<=1)
    {
        return s;
    }
    int dp[1000][1000]={0};//状态矩阵,1表示i到j是回文子串,0表示不是回文串
    int begin=0,end=0;//标识回文子串的开始和结束下标
    int len=strlen(s);//原始字符串的长度
    int i=0,j=0;
    for(i=0;i<len-1;i++)//先完成计算长度为1和2的回文子串的状态标记
    {
        dp[i][i]=1;
        if(s[i]==s[i+1])//如果s[i]==s[i+1],那么i~i+1是回文串
        {
            dp[i][i+1]=1;
            begin=i;
            end=i+1;
        }
    }
    dp[len-1][len-1]=1;
    
    for(j=3;j<=len;j++)//j 表示回文子串的长度
    {
        int k=0;
        for(k=0;k<=len-j;k++)//从头开始遍历长度为j的子串是否是回文串
        {
            //printf("s[%d]=%c,s[%d]=%c\n",k,s[k],k+j-1,s[k+j-1]);
            if(s[k]==s[k+j-1])//如果s[k]==s[k+j-1],那么k~k+j-1是否是回文串由k+1~k+j-2来决定
            {
                if(dp[k+1][k+j-2]==1)
                {
                    dp[k][k+j-1]=1;
                    begin=k;
                    end=k+j-1;
                }
            }
        }
    }
    printf("begin=%d,end=%d,\n",begin,end);
    char *result=(char*)malloc(sizeof(char)*(end-begin+2));//返回回文子串
    for(j=begin;j<=end;j++)
    {
        result[j-begin]=s[j];
    }
    result[end-begin+1]='\0';
    printf("strlen(s)=%d,strlen(result)=%d,result=%s\n",len,(end-begin+2),result);
    return result;    
}

以下内容来自https://www.cnblogs.com/coderJiebao/p/Algorithmofnotes30.html

下面介绍动态规划的方法,使用动态规划可以达到最优的 O(n2) 复杂度。

  令 dp[i][j] 表示 S[i] 至 S[j] 所表示的子串是否是回文子串,是则为 1,不是则为 0。这样根据 S[i] 是否等于 S[j] ,可以把转移情况分为两类:

    1.  若 S[i] == S[j],那么只要 S[i+1] 至 S[j-1] 是回文子串,S[i] 至 S[j] 就是回文子串;如果S[i+1] 至 S[j-1] 不是回文子串,则 S[i] 至 S[j] 也不是回文子串。
    2.  若 S[i] != S[j],那么 S[i] 至 S[j] 一定不是回文子串。    

  由此可以写出状态转移方程

          dp[i][j]={dp[i+1][j−1],S[i]==S[j]0,S[i]!=S[j]

  边界:dp[i][i]=1,dp[i][i+1] = (S[i] == S[i+1]) ? 1 : 0。

  根据递推写法从边界出发的原理,注意到边界表示的是长度为 1 和 2 的子串,且每次转移时都对子串的长度减了 1,因此不妨考虑按子串的长度和子串的初始位置进行枚举,即第一遍将长度为 3 的子串的 dp 值全部求出,第二遍通过第一遍结果计算出长度为 4 的子串的 dp 值 ……

猜你喜欢

转载自blog.csdn.net/y___y___/article/details/81586401
今日推荐