一、题目概要
给定一个字符串 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);
}
};