题目描述:
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例2:
输入: “cbbd”
输出: “bb”
解题思路:
首先观察回文数的特征,每一个回文字符串(长度大于)去掉头尾之后都是一个新的回文串,所以判断一个字符串是回文串,可以通过判定其去掉头尾部分是一个回文串,且头尾相同。由此,可以整理出动态规划的解决方案。设 dp[ i ][ j ] 为原字符串s从 索引i 到 j 的字符子串是否为回文子串(true Or false)。状态转移方程:dp[ i ][ j ] = dp[ i+1 ][ j-1 ] && s.toCharArray()[ i ] == s.toCharArray()[ j ]。
边界条件:
- dp[ i ][ i ]=true
- dp[ i ][ i+1 ]=(s.toCharArray()[ i ] == s.toCharArray()[ i+1 ] )
因为使用了双重循环,所以时间复杂度为O(n2)
代码:
public static String longestPalindrome(String s) {
int len = s.length();
//前置判断,如果字符串长度为1,就直接返回该字符串
if (len < 2){
return s;
}
//maxLen用于记录最长回文子串的长度
int maxLen = 1;
//截取字符串起始位置
int begin = 0;
//设置边界条件
boolean[][] dp = new boolean[len][len];
for (int i = 0; i < len; i++) {
dp[i][i] = true;
}
char[] chars = s.toCharArray();
for (int j = 1; j < len; j++) {
//二重循环,用i来寻找与j相同的元素,并做标记
for (int i = 0; i < j; i++) {
//状态转移方程的第一个判断,s.toCharArray()[i] == s.toCharArray()[j]
if (chars[i] != chars[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] = 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);
}