题目描述

题目链接:5. 最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串。

如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。

示例1:

1
2
3
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例2:

1
2
输入:s = "cbbd"
输出:"bb"

提示:

  • 1 <= s.length <= 1000
  • s 仅由数字和英文字母组成

我的题解

方法一:动态规划

思路

假设dp[i][j]表示字符串s下标从i~j的子字符串是否为回文串,那么有以下转移方程:

  • i==j,表示子字符串有一个字符,为回文串,因此dp[i][j]=true
  • i==j-1,表示子字符串有两个字符
    • s[i]==s[j],则dp[i][j]=true
    • s[i]!=s[j],则dp[i][j]=false
  • 否则表示子字符串拥有两个以上字符
    • s[i]==s[j]并且dp[i+1][j-1]==true,则dp[i][j]=true
    • 否则dp[i][j]=false

在具体编写代码时需要考虑两个问题:

  1. 由于子字符串必定存在,因此j >= i
  2. 由于dp[i][j] = (s[i]==s[j] && dp[i+1][j-1]==true),因此在遍历dp数组时,应从左下角开始遍历。

图示第二个问题,假设字符串长度为5:

暂时无法在飞书文档外展示此内容

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public String longestPalindrome(String s) {
int m = s.length(), start = 0, end = 0;
boolean[][] dp = new boolean[m][m];
for (int i = m - 1; i >= 0; i--) {
for (int j = i; j < m; j++) {
boolean b = (s.charAt(i) == s.charAt(j));
if (j - i <= 1) {
// 子字符串为一个字符或两个字符组成的情况
dp[i][j] = b;
} else if (i + 1 < m && j - 1 >= 0) {
// 子字符串为两个以上字符组成的情况
dp[i][j] = (b && dp[i + 1][j - 1]);
}
// 记录子字符串位置
if (dp[i][j] && j - i > end - start) {
start = i;
end = j;
}
}
}
return s.substring(start, end + 1);
}
}

方法二:中心扩展法

思路

观察回文串我们发现:

  • 只有一个字符的为回文串
  • 有两个字符并且两个字符相同的字符串为回文串
  • 其他回文串都由一个字符或两个字符扩展而成

因此,我们可以遍历字符串,以当前字符,以及当前字符和相邻字符为中心,向两边扩展,直到不能扩展为止。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public String longestPalindrome(String s) {
int max = 0, start = 0, end = 0;
for (int i = 0; i < s.length() - 1; i++) {
// 以当前字符为中心向两边扩展
int len1 = expand(s, i, i);
// 以当前字符与相邻字符为中心向两边扩展
int len2 = expand(s, i, i + 1);
int len = Math.max(len1, len2);
if (max < len) {
max = len;
// 重新计算子字符串位置
start = i - (len - 1) / 2;
end = i + len / 2;
}
}
return s.substring(start, end + 1);
}

private int expand(String s, int left, int right) {
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
left--;
right++;
}
return right - left - 1;
}

}