题目描述
给你一个字符串 s
,找到 s
中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
提示:
1 <= s.length <= 1000
s
仅由数字和英文字母组成
解法
动态规划解法。
思路:
对于一个子串而言,如果它是回文串,并且长度大于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。
只有 s[i+1:j−1]是回文串,并且 s 的第 i 和 j 个字母相同时,s[i:j] 才会是回文串。
边界:1. 长度为 1 的子串,它是个回文串
2. 长度为 222 的子串,只要它的两个字母相同,它就是一个回文串
最终的答案即为所有 P(i,j)=true 中 j−i+1(即子串长度)的最大值
java代码:
java
class Solution {
public String longestPalindrome(String s) {
// 字符串长度小于2,直接返回长度(0或1)
int len = s.length();
if (len < 2) {
return s;
}
// 初始化最长回文子串的长度为1
int maxLen = 1;
// 初始化最长回文子串的开始索引为0
int begin = 1;
// 维护子串是否是回文子串的状态列表,二维数组,分别是开始索引和结束索引
boolean[][] dp = new boolean[len][len];
// 初始化:所有长度为 1 的子串都是回文串
for (int i = 0; i < len; i++) {
dp[i][i] = true;
}
// 开始遍历,我们可以从第二个开始
for (int i = 1; i < len; i++) { // 子串右边界
for (int j = 0; j < i; j++) { // 子串左边界
// 如果两个不相等,则一定不是回文子串
if (s.charAt(i) != s.charAt(j)) {
dp[j][i] = false;
} else {
// 如果两个相等
// 如果就两个元素,则是true
if (i - j < 3) {
dp[j][i] = true;
} else {
// 如果大于两个元素,则看他的子串是不是回文子串,子串是回文子串,他就是回文子串
dp[j][i] = dp[j + 1][i -1];
}
}
// 更新最大长度,如果当前子串是回文子串,并且长度大于前面的最大长度,就更新最大长度和起始索引
if (dp[j][i] && (i - j + 1 > maxLen)) {
maxLen = i - j + 1;
begin = j;
}
}
}
return s.substring(begin, begin + maxLen);
}
}
复杂度
时间复杂度:O(n^2)
,n为字符串长度。
空间复杂度:O(n^2)
,即存储动态规划状态需要的空间。