题目描述
方法一:动态规划 O(N2) O(N2)
思路
boolean dp[i][j]表示字符串s[i,j]是不是回文串 状态转移方程的思考- 如果
dp[i+1][j-1]为true,并且s[i]=s[j],则dp[i][j]也为true。 - 下一步,需要考虑边界情况,
i+1 <= j-1必须成立,即j-i >= 2。j-i < 2的情况为s[i,j]为单个字符或者为两个字符。 - 所以得出状态转移方程:
dp[i][j] = (s[i]=s[j]) && (dp[i+1][j-1] || j - i <= 1)或者画图理解状态转移方程
class Solution {
public String longestPalindrome(String s) {
int l = s.length();
boolean[][] dp = new boolean[l][l];
int max = 1, start = 0;
// 由于是参考左下方,所以需要从上到下填写(i)
for (int j = 0; j < l; j++) {
for (int i = 0; i < j + 1; i++) { // 需要覆盖 i = j, 单个元素
if (s.charAt(i) != s.charAt(j)) {
dp[i][j] = false;
} else {
if (j - i <= 1) {//没有左下方参考的格子,一个字符或两个字符
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];//当前字符串至少有三个字符,可以两头减,参考左下方的格子
}
//确定完dp[i][j]为回文了,计算长度
if (dp[i][j] && j - i + 1 > max) {
max = j - i + 1;
start = i;
}
}
}
}
return s.substring(start, start + max);
}
}
方法二:中心扩展 O(N2) O(1)
和暴力枚举判断法正好相反
class Solution {
public String longestPalindrome(String s) {
int length = s.length();
if (length <= 1) {
return s;
}
int maxLength = 1;
int begin = 0;
for (int i = 0; i < length; i++) {//遍历字符串s,把每一位都当作扩展的中心
int pLengthOdd = expand(s, i, i);//以i为索引的数为中心,扩展寻找奇数回文串
int pLengthEven = expand(s, i, i + 1);//以i为索引的数为中心,扩展寻找偶数回文串
int pLength = Math.max(pLengthOdd, pLengthEven);
if (pLength > maxLength) {
maxLength = pLength;
begin = i - (maxLength - 1) / 2;
}
}
return s.substring(begin, begin + maxLength);
}
//扩展搜索,返回最长的回文子串
public int expand(String s, int left, int right) {
while (left >= 0 && right <= s.length() - 1) {
if (s.charAt(left) == s.charAt(right)) {
left--;
right++;
} else {
break;
}
}
return right - left - 1;//注意这里的返回值
}