指尖划过的轨迹,藏着最细腻的答案~
题目:
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
提示:
1 <= s.length <= 1000
s 仅由数字和英文字母组成
分析:
动态规划一般分为3步走:
-
确定dp数组含义: 我们定义
dp[i][j]为从下标i到下标j的子串是否是回文串。 -
状态转移方程: 寻找子问题,对于
dp[i][j]来说,如果dp[i+1][j-1]为回文串,什么情况下dp[i][j]才会是回文串呢?例如:字符串"abcba","bcb"是回文串,两边相同时会是一个新的回文串,因此可得状态转移方程: -
初始化: 我们思考一下,如果字符串长度为1,那直接就是回文串; 如果长度为2,是否可以使用上面状态转移方程呢,答案是不可以,我们没有办法分左右,所有当长度为2时,需要直接判断,两个字符相等即为回文串。
具体的实现时,需要两个循环:
- 外层循环主要是遍历字符串的长度L,从3开始;
- 内层循环遍历左边界i;右边界
j = i + L - 1; - 同时需要维护最长的子串长度maxLengeh=1;
AC代码:
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size();
if (n < 2) {
return s;
} else if (n == 2) {
return s[0] == s[1] ? s : string(1, s[0]);
}
vector<vector<bool>> dp(n, vector<bool>(n, false));
for (int i = 0; i < n; i++) {
dp[i][i] = true;
}
int begin = 0, maxLength = 1;
for (int L = 2; L <= n; L++) {
for (int i = 0; i < n; i++) {
int j = i + L - 1;
if (j >= n) {
break;
}
if (s[i] == s[j]) {
if (j - i < 3) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i+1][j-1];
}
}
if (dp[i][j] && L > maxLength) {
maxLength = L;
begin = i;
}
}
}
return s.substr(begin, maxLength);
}
};