最長回文子串 (動態規划法、中心擴展算法)


問題描述:

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

 

思考:

嗯,回文嘛!就是順序讀取和逆序讀取的結果是一樣的,那我們可以使用兩個for循環來不斷的截取給定的字符串S,然后判斷截取后的字符串是不是回文串,與此同時,使用一個新的字符串result來保存我們截取到的並且長度最長的回文串。

 

代碼:

public String longestPalindrome_reconstructure1(String s){ // 超出時間限制
        if (s.length() < 2){
            return s;
        }
        String result = s.substring(0,1);
        String temp = null;
        String temp1 = null;
        for(int i = 0; i < s.length() - 1; i++){
            temp = null;
            temp1 = null;
            for (int j = s.length(); j > i; j--){
                if (j - i < result.length()) break;
                temp = s.substring(i, j);
                temp1 = new StringBuilder(temp).reverse().toString(); // 對截取后的字符串進行反轉

                if (temp.equals(temp1) && temp.length() > result.length()){
                    result = temp;
                }
            }
        }
        return result;
    }

 

上述代碼倒是完成了得到最長回文子串的功能,但是,有個很明顯的缺點就是時間開銷太大了,所以肯定得想想辦法減小時間開銷

 

使用中心擴展算法:

我們觀察到回文中心的兩側互為鏡像。因此,回文可以從它的中心展開,並且只有 2n - 1個這樣的中心。

你可能會問,為什么會是 2n - 1 個,而不是 n個中心?原因在於所含字母數為偶數的回文的中心可以處於兩字母之間(例如 :“abba” 的中心在兩個b之間),時間復雜度也只有O(n​2​​)

代碼:

// 使用中心擴展算法
    public String longestPalindrome_reconstructure2(String s) { // 第二次對代碼進行重構
        if (s.length() < 2) { // 單個字符肯定是回文串,直接返回s
            return s;
        }
        int maxLength = 0;
        int center = 0;
        for (int i = 0; i < s.length(); i++){
            int begin = centerExpand(s, i, i);          // 最長回文串長度為奇數
            int end = centerExpand(s, i, i + 1);   // 最長回文串長度為偶數

            if (maxLength < Math.max(begin, end)){
                center = i;                                // 以center為中心
                maxLength = Math.max(begin, end);          // 最長回文串長度
            }
        }
        // 如果我們的回文串的長度為偶數,那么中心左邊的長度會比右邊的長度小1
        return s.substring(center - (maxLength - 1) / 2, center + maxLength / 2 + 1);
    }

    int centerExpand(String s, int begin, int end){
        int left = begin, right = end;
        while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)){
            left--;
            right++;
        }
        // 返回以begin,end為基准,同時向左向右擴展后能夠得到的最長回文串長度
        return right - left - 1;
    }

使用動態規划法:

避免在驗證回文時進行不必要的重復計算。考慮 “ababa” 這個示例。如果我們已經知道 “bab” 是回文,那么很明顯,“ababa” 一定是回文,因為它的左首字母和右尾字母是相同的。

P(i,j)=(P(i+1,j−1) and S​i​​==S​j​​)

我們首先初始化一字母和二字母的回文,然后找到所有三字母回文,並依此類推…

R%`HVT[3D88A86WRHC5CM5Q

代碼:

// 使用動態規划法
    public String longestPalindrome_reconstructure3(String s) { // 第三次對代碼進行重構
        if (s.length() < 2) { // 單個字符肯定是回文串,直接返回s
            return s;
        }
        boolean[][] dp = new boolean[s.length()][s.length()];  // 初始化一個二維數組,值默認是false
        String result = s.substring(0,1);
        for (int j = 0; j < s.length(); j++){
            for (int i = 0; i <= j; i++){
                dp[i][j] = s.charAt(i) == s.charAt(j) &&(j - i <= 2 || dp[i+1][j-1]);
                if (dp[i][j]){
                    if (j - i + 1 > result.length()){
                        result = s.substring(i, j + 1);
                    }
                }
            }
        }
        return result;
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM