方法一 动态规划
思路: 对于一个字串而言,如果它是回文串,并且长度大于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。
根据这样的思路,我们就可以用动态规划的方法解决本题。我们用 P(i,j) 表示字符串 s 的第 i 到 j 个字母组成的串(下文表示成 s[i:j])是否为回文串:
这里的「其它情况」包含两种可能性:
- s[i,j] 本身不是一个回文串;
- i > j,此时 s[i,j] 本身不合法。
写出动态规划的状态转移方程:
写出动态规划的边界条件:
根据这个思路,我们就可以完成动态规划了,最终的答案即为所有 P(i,j)=true 中 j-i+1(即子串长度)的最大值。注意:在状态转移方程中,我们是从长度较短的字符串向长度较长的字符串进行转移的,因此一定要注意动态规划的循环顺序。
class Solution {
public String longestPalindrome(String s) {
int n = s.length();
if(n < 2) return s; //如果只有1位直接返回
int maxLen = 1; //记录最大回文串的长度
int begin = 0; //记录最大回文串开始的下标
// dp[i][j] 表示 s[i..j] 是否是回文串
boolean[][] dp = new boolean[n][n];
// 初始化:所有长度为 1 的子串都是回文串
for(int i = 0; i < n; i++){
dp[i][i] = true;
}
char[] charArray = s.toCharArray();
// 递推开始
// 先枚举子串长度
//L表示回文串长度,l表示左边下标,r表示右边下标
for(int L = 2; L <= n; L++){
for(int l = 0; l < n; l++){
int r = L + l - 1; //因为 r - l + 1 = L
if(r >= n){
break;
}
if (charArray[l] != charArray[r]) {
dp[l][r] = false;
}else{
if(r - l < 3){
dp[l][r] = true;
}else{
dp[l][r] = dp[l + 1][r - 1];
}
}
if(dp[l][r] && r - l + 1 > maxLen){
maxLen = r - l + 1;
begin = l;
}
}
}
return s.substring(begin, begin + maxLen);
}
}