📜  最长回文子串的长度(1)

📅  最后修改于: 2023-12-03 15:40:17.051000             🧑  作者: Mango

最长回文子串的长度

回文串是一种具有对称性质的字符串,即正反读都一样。最长回文子串就是一个字符串中最长的回文子串。在计算机领域中,字符串的问题是经常遇到的问题之一,最长回文子串也是常见的问题之一。

解法

目前求解最长回文子串的方法较为多样,以下为常见的几种解法:

中心扩展法

遍历每个字符,并以其为中心点,向两侧扩展,找到最长回文串。这样的时间复杂度为 $O(n^2)$。

public static int longestPalindrome(String s) {
    if (s == null || s.length() == 0) {
        return 0;
    }
    int max = 1;
    for (int i = 0; i < s.length() - 1; i++) {
        int len1 = expandCenter(s, i, i);
        int len2 = expandCenter(s, i, i + 1);
        max = Math.max(max, Math.max(len1, len2));
    }
    return max;
}

public static int expandCenter(String s, int left, int right) {
    while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
        left--;
        right++;
    }
    return right - left - 1;
}
动态规划法

通过状态转移方程求解,时间复杂度为 $O(n^2)$ 。

public static int longestPalindrome(String s) {
    if (s == null || s.length() == 0) {
        return 0;
    }
    int n = s.length();
    boolean[][] dp = new boolean[n][n];
    int max = 1;

    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 < 3) {
                    dp[i][j] = true;
                } else {
                    dp[i][j] = dp[i + 1][j - 1];
                }
            } else {
                dp[i][j] = false;
            }

            if (dp[i][j]) {
                max = Math.max(max, j - i + 1);
            }
        }
    }
    return max;
}
Manacher 算法

时间复杂度为 $O(n)$ 。

public static int longestPalindrome(String s) {
    if (s == null || s.length() == 0) {
        return 0;
    }
    char[] newStr = new char[(s.length() << 1) + 1];
    int[] p = new int[newStr.length];
    int max = 1;

    for (int i = 0; i < s.length(); i++) {
        newStr[i << 1] = '#';
        newStr[(i << 1) + 1] = s.charAt(i);
    }
    newStr[newStr.length - 1] = '#';

    int right = 0, center = 0;
    for (int i = 0; i < newStr.length; i++) {

        if (i < right) {
            p[i] = Math.min(right - i, p[(center << 1) - i]);
        } else {
            p[i] = 1;
        }

        while (i >= p[i] && i + p[i] < newStr.length && newStr[i - p[i]] == newStr[i + p[i]]) {
            p[i]++;
        }

        if (i + p[i] > right) {
            right = i + p[i];
            center = i;
        }
        max = Math.max(max, p[i]);
    }

    return max - 1;
}
总结

以上三种方法都能较为高效地解决最长回文子串的问题。中心扩展法是最简单粗暴的方法,动态规划法通过递推求解,Manacher 算法则是从回文子串的对称性入手,优化时间复杂度。根据具体的场景可以选择不同的方法解决问题。