public class Solution {
/**
* 寻找字符串中的最长回文子串(动态规划解法)
* @param s 输入字符串
* @return 最长回文子串
*/
/*
回文的核心特征是 对称性。一个字符串要成为回文,必须满足:
1.首尾字符相同
2.去掉首尾后的子串仍然是回文
*/
public String longestPalindrome(String s) {
// ====== 特殊情形处理 ======
int len = s.length();
if (len < 2) {
return s; // 长度0或1时直接返回自身
}
// ====== 初始化记录变量 ======
int maxLen = 1; // 当前发现的最长回文长度(最小值为1)
int begin = 0; // 最长回文的起始索引
// ====== DP表格初始化 ======
// dp[i][j]表示s的子串[i..j]是否为回文
boolean[][] dp = new boolean[len][len]; // 默认值false
char[] charArray = s.toCharArray(); // 转为字符数组便于快速访问
// 初始化单字符回文(所有长度为1的子串都是回文)
for (int i = 0; i < len; i++) {
dp[i][i] = true; // 对角线置为true
}
// ====== 动态规划填表 ======
for (int j = 1; j < len; j++) { // 右边界j从1开始
for (int i = 0; i < j; i++) { // 左边界i始终小于j
/* 情况1:首尾字符不同 */
if (charArray[i] != charArray[j]) {
dp[i][j] = false;
}
/* 情况2:首尾字符相同 */
else {
/* 子串长度判断(关键优化):
- 长度2/3的子串(i,j相邻或间隔1个字符)
- 此时首尾相同即构成回文 */
if (j - i < 3) {
dp[i][j] = true;
}
/* 长度>3的子串:状态转移 */
else {
// 当前子串是否是回文 = 内部子串是否是回文
dp[i][j] = dp[i + 1][j - 1];
}
}
/* 发现更长回文时更新记录 */
if (dp[i][j] && (j - i + 1 > maxLen)) {
maxLen = j - i + 1; // 计算当前回文长度
begin = i; // 记录起始位置
}
}
}
// ====== 返回结果 ======
return s.substring(begin, begin + maxLen);
}
}