题目要求
给你一个字符串 s,找到 s 中最长的回文子串。
(回文串就是正着读和反着读都一样的字符串)
- 1 <= s.length <= 1000
- s 仅由数字和英文字母(大写和/或小写)组成
版本一:一种凭借直觉但是超时的算法
class Solution {
public:
string longestPalindrome(string s) {
unsigned maxSize = 0;
string maxHuiWen;
for (size_t i = 0; i < s.length(); i++)
{
for (size_t j = i+1; j <= s.length(); j++)
{
if ((j-i > maxSize) && isHuiWen(s.substr(i, j-i)))
{
maxSize = j - i;
maxHuiWen = s.substr(i, j - i);
}
}
}
return maxHuiWen;
}
bool isHuiWen(const string &s)
{
if (string(s.rbegin(), s.rend()) == s)
{
return true;
}
return false;
}
};
整体思路
先构造一个判断字符串是否是回文串的函数。对于给定的字符串s,找出该s的所有子串,调用回文判断函数找出最长的回文子串。
版本二:动态规划
class Solution {
public:
string longestPalindrome(string s) {
int lenth = s.length(), maxlenth = 0;
string maxHuiWen;
//初始化dp表
bool** dp;
dp = new bool*[lenth];
for (size_t i = 0; i < lenth; i++)
{
dp[i] = new bool[lenth];
}
for (size_t i = 0; i < lenth; i++)
{
for (size_t j = i; j < lenth; j++)
{
if (i == j)
{
dp[i][j] = true;
}
else
dp[i][j] = false;
}
}
//当使用递减for循环时,不能使用unsigned i>=0;
for (int i = lenth-1; i >= 0; i--)
{
for (int j = lenth-1; j >= i; j--)
{
//首尾相同
if (s[i] == s[j])
{
//子串是回文串 或者 没有子串
if (i+1 >= j-1 || dp[i+1][j-1] == true)
{
dp[i][j] = true;
if (j - i + 1 > maxlenth)
{
maxlenth = j - i + 1;
maxHuiWen = s.substr(i, j - i + 1);
}
}
}
}
}
return maxHuiWen;
}
};
整体思路
对于一个回文串,它的首尾字符是相同的。并且在去掉首尾字符后,剩下的字符组成的字符串还是一个回文串。利用这个性质进行动态规划。
首先初始化dp表,设置给定字符串中长度为1的子串为回文串,也就是true。
状态转移:对于str[i,j] (从i开始到j结束) 的字符子串。如果第i位和第j位的字符首尾相同,并且从i+1到j-1的子串是回文串,则该子串为回文串。
从dp表的尾端开始构造到头端,最后将整个dp表构造完毕。
学到了什么
1、重新熟悉了动态规划的思想和dp表的构建
2、对于递减的for循环,不能用unsigned i 以及 i>0 来控制循环的结束。因为unsigned始终大于0.此时只能使用int来控制for循环的结束。
3、二维数组的动态申请方法:
bool** dp;
dp = new bool*[lenth]; //提前给定一个lenth
for (size_t i = 0; i < lenth; i++)
{
dp[i] = new bool[lenth];
}