5. 最长回文子串
给你一个字符串 s
,找到 s
中最长的回文子串。
示例1:
输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。
示例2:
输入:s = "cbbd" 输出:"bb"
思路:动态规划
- 回文的意思是正着念和倒着念一样,如:上海自来水来自海上;
- 对于一个子串而言,如果它是回文串,并且长度大于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串;dp[i][j] = dp[i + 1][j - 1]
- 对于长度为 1 的子串,它显然是个回文串;对于长度为 2 的子串,只要它的两个字母相同,它就是一个回文串;
- 先枚举子串长度,从len=2开始;
- 然后从0开始枚举左边界(由L和i可以确定字符串的右边界,即j=i+L-1),若是右边界越界则退出当前循环;
-
根据这个思路,我们就可以完成动态规划了,最终的答案即为所有 P(i, j) =true 中 j-i+1(即子串长度)的最大值。dp[i][j] && j - i + 1 > maxLen
注意:在状态转移方程中,我们是从长度较短的字符串向长度较长的字符串进行转移的,因此一定要注意动态规划的循环顺序。
public class Solution {
public String longestPalindrome(String s) {
int len = s.length();
if (len < 2) {
return s;
}
int maxLen = 1;
int begin = 0;
// dp[i][j] 表示 s[i..j] 是否是回文串
boolean[][] dp = new boolean[len][len];
// 初始化:所有长度为 1 的子串都是回文串
for (int i = 0; i < len; i++) {
dp[i][i] = true;
}
char[] charArray = s.toCharArray();//toCharArray() 方法将字符串转换为字符数组。
// 递推开始
// 先枚举子串长度
for (int L = 2; L <= len; L++) {
// 枚举左边界,左边界的上限设置可以宽松一些
for (int i = 0; i < len; i++) {
// 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
int j = L + i - 1;
// 如果右边界越界,就可以退出当前循环
if (j >= len) {
break;
}
if (charArray[i] != charArray[j]) {
dp[i][j] = false;
} else {
if (j - i < 3) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];
}
}
// 只要 dp[i][j] == true 成立,就表示子串 s[i..j] 是回文,此时记录回文长度和起始位置
if (dp[i][j] && j - i + 1 > maxLen) {
maxLen = j - i + 1;
begin = i;
}
}
}
return s.substring(begin, begin + maxLen);
}
}