开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第22天,点击查看活动详情
5. 最长回文子串 题目描述:给你一个字符串 s,找到 s 中最长的回文子串。
| 示例1 | 示例2 |
|---|---|
输入:s = "babad" 输出: "bab" 解释: "aba" 同样是符合题意的答案。 | 输入:s = "cbbd" 输出: "bb" |
中规中矩的动态规划
达成共识:
1、单个字符一定是“回文串”;
2、如果字符串 在 区间是回文串,且 ,那么 在 区间也必定是回文串,其中,,。
1、确定 dp 状态数组
定义 表示字符串 在 区间是否是回文串,每个元素值为 / 。
🎡 NOTE: 这里是 左闭右闭 区间。
2、确定 dp 状态方程
这里要讨论一下 、 的相对大小:
-
当 不能构成区间时,此时存在 (通过 得到),此时 是否能成为回文串仅仅取决于 ;
-
当 时, 不仅取决于 ,还要判断 是否是回文串,即 = 。
3、确定 dp 初始状态
通过 单个字符一定是“回文串” 可知,,其中 。
4、确定遍历顺序
-
外层循环从 遍历
-
内层循环从 遍历到
5、确定最终返回值
由于题目要求我们返回具体的回文串,所以我们需要额外记录一下最长回文串的 起始位置(begin) 和 最大长度(maxLength); 每当 而且 时,将 赋值给 ,将 赋值给 ,其中 。
所以最终返回值为
6、代码示例
/**
* 空间复杂度 O(n^2)
* 时间复杂度 O(n^2)
*/
function longestPalindrome(s: string): string {
const n = s.length;
if (n < 2) {
return s;
}
const dp = Array.from({ length: n }, () => new Array(n).fill(false));
let begin = 0;
let maxLength = 1;
for (let k = 0; k < n; k++) {
dp[k][k] = true;
}
for (let j = 1; j < n; j++) {
for (let i = 0; i < j; i++) {
if (s[i] !== s[j]) {
dp[i][j] = false;
} else if (j - i < 3) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];
}
const currLength = j - i + 1;
if (dp[i][j] && currLength > maxLength) {
begin = i;
maxLength = currLength;
}
}
}
return s.slice(begin, begin + maxLength);
};