[算法]死磕最長迴文子串

題目

給定一個字符串 s,找到 s 中最長的迴文子串。你能夠假設 s 的最大長度爲 1000。php

示例 1:算法

輸入: "babad"
輸出: "bab"
注意: "aba" 也是一個有效答案。
示例 2:網絡

輸入: "cbbd"
輸出: "bb"spa

來源:力扣(LeetCode)
連接:https://leetcode-cn.com/problems/longest-palindromic-substring
著做權歸領釦網絡全部。商業轉載請聯繫官方受權,非商業轉載請註明出處。code

思路

思路1

基於中心點枚舉的算法,時間複雜度是O(n^2)。blog

先肯定中間的點,這裏包括兩種,中間只有一個元素,或者中間有兩個元素。leetcode

思路2

基於動態規劃的算法,時間複雜度 O(n^2),會耗費額外的 O(n^2) 的空間複雜度。字符串

dp[i][j],i <= j,表示從i到j是不是迴文串,get

狀態轉移方程是dp[i][j] = dp[i + 1][j - 1] && s[i] = s[j]。string

思路3

使用 Manancher's Algorithm,能夠在 O(n) 的時間內解決問題。

參考資料:https://www.felix021.com/blog/read.php?2040

這個方法雖然最優,感受通常人很難想到。

代碼

方法1

class Solution {
    public String longestPalindrome(String s) {
        if(s == null || s.length() == 0){
            return "";
        }
        int start = 0, len = 0, longest = 1;
        for (int i = 0; i < s.length(); i++) {
            len = longestPalindromeLength(s, i, i);
            if (len > longest) {
                longest = len;
                start = i - len / 2;
            }

            len = longestPalindromeLength(s, i, i + 1);
            if (len > longest) {
                longest = len;
                start = i - len / 2 + 1;
            }
        }
        return s.substring(start, start + longest);
    }

    public int longestPalindromeLength(String s, int left, int right) {
        int len = 0;
        while (left >= 0 && right < s.length()) {
            if (s.charAt(left) != s.charAt(right)) {
                break;
            }
            len += left == right ? 1 : 2;
            left--;
            right++;
        }
        return len;
    }
}

方法2

class Solution {
    public String longestPalindrome(String s) {
        if (s == null || s.length() == 0) {
            return "";
        }
        int start = 0, longest = 1;

        int n = s.length();
        boolean dp[][] = new boolean[n][n];

        for (int i = 0; i < n; i++) {
            dp[i][i] = true;
        }

        for (int i = 0; i < n - 1; i++) {
            dp[i][i + 1] = s.charAt(i) == s.charAt(i + 1);
            if(dp[i][i + 1]){
                start = i;
                longest = 2;
            }
        }

        for (int i = n - 3; i >= 0; i--) {
            for (int j = i + 2; j < n; j++) {
                dp[i][j] = dp[i + 1][j - 1] && s.charAt(i) == s.charAt(j);
                if(dp[i][j] && longest < j - i + 1){
                    start = i;
                    longest = j - i + 1;
                }
            }
        }


        return s.substring(start, start + longest);
    }
}
相關文章
相關標籤/搜索