LeetCode小算法記錄(五十)最長迴文子串

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

示例 1:

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

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

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/longest-palindromic-substring
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。

解題思路:
本題最容易想到的一種方法應該就是 中心擴散法。
中心擴散法怎麼去找回文串?
從每一個位置出發,向兩邊擴散即可。遇到不是迴文的時候結束。舉個例子,str = acdbbdaastr=acdbbdaa 我們需要尋找從第一個 b(位置爲 33)出發最長迴文串爲多少。怎麼尋找?
首先往左尋找與當期位置相同的字符,直到遇到不相等爲止。
然後往右尋找與當期位置相同的字符,直到遇到不相等爲止。
最後左右雙向擴散,直到左和右不相等。如下圖所示:

每個位置向兩邊擴散都會出現一個窗口大小(len)。如果 len>maxLen(用來表示最長迴文串的長度)。則更新 maxLen 的值。
因爲我們最後要返回的是具體子串,而不是長度,因此,還需要記錄一下 maxLen 時的起始位置(maxStart),即此時還要 maxStart=len。

public String longestPalindrome1(String s) {

        if (s == null || s.length() == 0) {
            return "";
        }
        int strLen = s.length();
        int left = 0;
        int right = 0;
        int len = 1;
        int maxStart = 0;
        int maxLen = 0;

        for (int i = 0; i < strLen; i++) {
            left = i - 1;
            right = i + 1;
            while (left >= 0 && s.charAt(left) == s.charAt(i)) {
                len++;
                left--;
            }
            while (right < strLen && s.charAt(right) == s.charAt(i)) {
                len++;
                right++;
            }
            while (left >= 0 && right < strLen && s.charAt(right) == s.charAt(left)) {
                len = len + 2;
                left--;
                right++;
            }
            if (len > maxLen) {
                maxLen = len;
                maxStart = left;
            }
            len = 1;
        }
        return s.substring(maxStart + 1, maxStart + maxLen + 1);

    }

作者:reedfan
鏈接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zhong-xin-kuo-san-fa-he-dong-tai-gui-hua-by-reedfa/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

優化:
中心擴散的方法,其實做了很多重複計算。動態規劃就是爲了減少重複計算的問題。動態規劃聽起來很高大上。其實說白了就是空間換時間,將計算結果暫存起來,避免重複計算。作用和工程中用 redis 做緩存有異曲同工之妙。
我們用一個 boolean dp[l][r] 表示字符串從 i 到 j 這段是否爲迴文。試想如果 dp[l][r]=true,我們要判斷 dp[l-1][r+1] 是否爲迴文。只需要判斷字符串在(l-1)和(r+1)兩個位置是否爲相同的字符,是不是減少了很多重複計算。
進入正題,動態規劃關鍵是找到初始狀態和狀態轉移方程。
初始狀態,l=r 時,此時 dp[l][r]=true。
狀態轉移方程,dp[l][r]=true 並且(l-1)和(r+1)兩個位置爲相同的字符,此時 dp[l-1][r+1]=true。

package leetCodeTest;

public class 最長迴文子串 {
    public static void main(String[] args) {
        String s = "babad";
        String s1 = longestPalindrome(s);
        System.out.println("s1 = " + s1);
    }
    /**
     * 傳統的區間規劃法,超時
     */
//    public static String longestPalindrome(String s) {
//        if (s.length() == 0 || s.length() == 1)
//            return s;
//        int len,i,j;
//        String res = "";
//        boolean flag = true;
//        for (len=1;len<=s.length();len++){
//            for (i=0;i+len<=s.length();i++){
//                String substring = s.substring(i, i + len);
//                flag = true;
//                for (j=0;j<substring.length()/2;j++){
//                    if (substring.charAt(j) != substring.charAt(substring.length()-1-j))
//                        flag = false;
//                }
//                if (flag && res.length() < substring.length())
//                    res = substring;
//
//            }
//        }
//        return res;
//    }

    /**
     * 中心擴散法+區間規劃
     * @param s
     * @return
     */
    public static String longestPalindrome(String s) {
        if (s == null || s.length() < 2) {
            return s;
        }
        int strLen = s.length();
        int maxStart = 0;  //最長迴文串的起點
        int maxEnd = 0;    //最長迴文串的終點
        int maxLen = 1;  //最長迴文串的長度

        boolean[][] dp = new boolean[strLen][strLen];

        for (int r = 1; r < strLen; r++) {
            for (int l = 0; l < r; l++) {
                if (s.charAt(l) == s.charAt(r) && (r - l <= 2 || dp[l + 1][r - 1])) {
                    dp[l][r] = true;
                    if (r - l + 1 > maxLen) {
                        maxLen = r - l + 1;
                        maxStart = l;
                        maxEnd = r;

                    }
                }

            }

        }
        return s.substring(maxStart, maxEnd + 1);

    }

}

作者:reedfan
鏈接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zhong-xin-kuo-san-fa-he-dong-tai-gui-hua-by-reedfa/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章