1. 程式人生 > 其它 >LeetCode/最長迴文子串

LeetCode/最長迴文子串

描述
對於長度為n的一個字串A(僅包含數字,大小寫英文字母),請設計一個高效演算法,計算其中最長迴文子串的長度。

思路
1.暴力列舉所有串,判斷串是否為迴文串並將當下最長的進行儲存

2.中心擴散,順序遍歷,對每個點進行左右同時擴散,得到其中心點對應的最大回文串和迴文串長度(考慮奇偶串要分別用一箇中心和兩個中心點進行遍歷),時間複雜度為O(n2),空間複雜度為O(1)

3.動態規劃,用二維dp陣列記錄任意兩點間是否為迴文串
狀態轉移方程:dp[i][j]=(s[i]==s[j])and dp[i+1][j-1]
邊界條件:j-i<3(即字串長度為2和3時不用再檢查子串)
合理的遞推順序(小串到大串)即能把任意兩點是否為迴文串計算出來
時間複雜度為O(n2),空間複雜度為O(n2)

4.Manacher演算法,中心擴散的時候可以結合動態規劃的思想,將已經擴散計算過的點進行儲存,使得演算法效能成為線性

中心擴散C++

點選檢視程式碼
class Solution {
public:
    string longestPalindrome(string s) {
        int maxlen = 1;//單字元進不了迴圈預設為1
        int begin,single,doubles;
        begin = 0;
        for(int i=0;i<s.length()-1;i++){
            single = fun(s,i,i);//奇串
            doubles = fun(s,i,i+1);//偶串
            //記錄最長字串對應起始位置
            if(single>maxlen&&single>doubles){
                maxlen = single;
                begin = i-maxlen/2;
            }
            else if(doubles>maxlen){
                maxlen = doubles;
                begin = i-maxlen/2+1;
            }
        }
        return string(s,begin,maxlen);
    }
//fun函式返回指定中心點的迴文串長度
 int fun(string &s,int begin,int end){
        while(begin>=0 && end<s.length() &&s[begin]==s[end]){
            begin--;
            end++;
        }
        return end-begin-1;
    }
};

動態規劃C++

點選檢視程式碼
class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        if (n < 2) {
            return s;
        }

        int maxLen = 1;
        int begin = 0;
        // dp[i][j] 表示 s[i..j] 是否是迴文串
        vector<vector<int>> dp(n, vector<int>(n));
        // 初始化:所有長度為 1 的子串都是迴文串
        for (int i = 0; i < n; i++) {
            dp[i][i] = true;
        }
        // 遞推開始
        // 先列舉子串長度
        for (int L = 2; L <= n; L++) {
            // 列舉左邊界,左邊界的上限設定可以寬鬆一些
            for (int i = 0; i < n; i++) {
                // 由 L 和 i 可以確定右邊界,即 j - i + 1 = L 得
                int j = L + i - 1;
                // 如果右邊界越界,就可以退出當前迴圈
                if (j >= n) {
                    break;
                }

                if (s[i] != s[j]) {
                    dp[i][j] = false;
                } else {
                    if (j - i < 3) {
                        dp[i][j] = true;
                    } else {
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }

                // 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是迴文,此時記錄迴文長度和起始位置
                if (dp[i][j] && j - i + 1 > maxLen) {
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substr(begin, maxLen);
    }
};