📅  最后修改于: 2023-12-03 14:55:22.918000             🧑  作者: Mango
最长回文子串是一个很经典的问题,它在编程面试和算法竞赛中经常被考察,因此掌握这个问题及其解法对程序员来说是非常重要的。
给定一个字符串,求出该字符串中的最长回文子串。回文串是指正着读和反着读都一样的字符串。
例如,对于字符串 "abcbad",其中最长的回文子串为 "abcba"。
最长回文子串问题可以通过动态规划或者中心拓展法来解决。
我们可以定义一个二维数组 $dp$,其中 $dp[i][j]$ 表示从索引 $i$ 到索引 $j$ 的子串是否是回文串。当 $dp[i][j]$ 是回文串时,如果 $j-i+1>maxLength$,则更新 $maxLength$ 和 $maxPalindrome$。
状态转移方程如下:
$$ dp[i][j] = \left{ \begin{array}{ll} true & \textrm{if } s_i=s_j \ false & \textrm{if } s_i \neq s_j \ dp[i+1][j-1] & \textrm{if } s_i=s_j \textrm{ and } dp[i+1][j-1] = true \ false & \textrm{otherwise} \end{array} \right. $$
时间复杂度为 $O(n^2)$,空间复杂度为 $O(n^2)$。
我们可以枚举每一个可能的回文子串的中心,然后尽可能地向两边拓展,直到不能再拓展为止。
具体来说,我们从左到右枚举每个位置 $i$,然后分别以 $i$ 和 $(i,i+1)$ 为中心,向两边扩散,获取以当前中心为中心的最长回文子串。然后在所有的以不同中心获取到的最长回文子串中,取最长的回文子串即可。
时间复杂度为 $O(n^2)$,空间复杂度为 $O(1)$。
以下是动态规划的代码实现:
public String longestPalindrome(String s) {
int n = s.length();
boolean[][] dp = new boolean[n][n];
int maxLength = 1;
int start = 0;
for (int i = 0; i < n; i++) {
dp[i][i] = true;
}
for (int j = 1; j < n; j++) {
for (int i = 0; i < j; i++) {
if (s.charAt(i) == s.charAt(j)) {
if (j - i <= 2) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];
}
}
if (dp[i][j] && j - i + 1 > maxLength) {
maxLength = j - i + 1;
start = i;
}
}
}
return s.substring(start, start + maxLength);
}
以下是中心拓展法的代码实现:
public String longestPalindrome(String s) {
int n = s.length();
int maxLength = 1;
int start = 0;
for (int i = 0; i < n; i++) {
int len1 = expandAroundCenter(s, i, i);
int len2 = expandAroundCenter(s, i, i + 1);
int len = Math.max(len1, len2);
if (len > maxLength) {
maxLength = len;
start = i - (maxLength - 1) / 2;
}
}
return s.substring(start, start + maxLength);
}
private int expandAroundCenter(String s, int left, int right) {
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
left--;
right++;
}
return right - left - 1;
}