📜  最长回文子串 |设置 1(1)

📅  最后修改于: 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;
}