动态规划专栏:(二)最长回文串

文章目录

  • 一、题目概要
  • 二、题目理解
  • 三、解题思路

一、题目概要

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

示例 1:

输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:

输入: “cbbd”
输出: “bb”

二、题目理解

分析题目时思考用什么方法,最长回文串由一个个短回文串组成,这种利用之前的解来帮助后面的问题,想到用动态规划。

三、解题思路

动态规划问题有个要点:用什么来划分问题。

刚做这题时,我进入了一个误区,假设二维数组dp[i][j]表示字符串中,从下标i到下表j是否是回文串;我找的状态方程思路是:如果dp[i+1][j-1]是true并且s[i]==s[j],那么dp[i][j]即为真。这种思路是错误的.

错误的原因在于对于dp[0][j]这一层就无法再往下分了,所以这种将下表范围作为依据来划分问题是错误的。

既然下标范围划分不行,那还有什么别的方法呢?这一点困扰了我一些时间,后来想到下标其实也是字符串长度的一种表现形式,字符串问题中最根本的问题还是字符长度,因此想到利用利用字符长度来划分问题,即从长度为1开始。

剩下问题就很简单了,考虑到边界条件,利用状态转移方程即可解题。

源码如下:

class Solution {
public:
    string longestPalindrome(string s)
    {
        int strLen = s.length();
        int lenMax = 1;
        int ibegin = 0;
        //二维数组,dp[i][j]表示从下表i到j是否是回文字符串
        vector<vector<bool>> dp(strLen, vector<bool>(strLen, false));

        //每一个单个的字符都是回文
        for (int i = 0; i < strLen; i++)
        {
            dp[i][i] = true;
        }

        //两个重复的字母也是回文串
        for (int i = 0; i < strLen -1; i++)
        {
            if (s[i] == s[i + 1])
            {
                dp[i][i + 1] = true;
                lenMax = 2;
                ibegin = i;
            }
           
        }
        
        for (int len = 3; len <= strLen; len++)
        {
            for (int i = 0; i < strLen; i++)
            {
                int j = i + len - 1;//从i开始长度为len,到j为止的字符
                if (j >= strLen)
                    break;

                if (s[i] == s[j] && dp[i + 1][j - 1])
                {
                    dp[i][j] = true;
                    if (j - i + 1 > lenMax)
                    {
                        lenMax = j - i + 1;
                        ibegin = i;
                    }
                }
            }
        }
        return s.substr(ibegin, lenMax);
    }
};

你可能感兴趣的:(算法)