Longest Palindromic Substring

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.

     題目最暴力的方法是,枚舉字符串的所有子串,並一一檢測其是否爲迴文串,求出最長的的即可,這樣的暴力帶來的時間代價是O(N^2)的;所以要優化,可以考慮以某個點爲中心,向兩邊擴散,看以此點爲中心可以獲得的最大回文串,這樣的時間複雜度也還是O(N^2),但是相比第一種方法,複雜度已經降低了很多,在這種方法中要特別注意,迴文串是奇偶的區別對待,爲了解決這個奇偶問題,可以考慮給每個原字符的左右兩邊添加特殊字符,這樣就可以將奇偶問題統一處理,都變成基數問題處理,這樣,需要一個P[i]的來記錄以i爲中心,向左/右能夠移動的最大距離(包括i本身),舉例可以發現此時的P[i] - 1爲原字符串中,以i爲中心的迴文串長度;

   有了第二種方法,統一處理奇偶迴文串的思路,仔細分析,可以發現,其實在求解P[i]的時候,有時候計算是可以直接利用i之前的結果避免,這就是傳說的Manacher算法,Manache算法對於P[i]的意思與第二種方法一致;關鍵是Manacher算法優化了P[i]的求解過程。其增加一箇中心點id,以及以id爲中心的迴文串能夠到達的右邊界max;分析可以發現,當i < max時,可以找到i關於id的對稱點j = id - (i - id) = 2 * id - i,如果P[j]小於max - i 的話,那麼一定有p[j] = p[i];如果p[j] > max - i, 那麼至少可以保證,在max - i的範圍內的字符串,是關於i對稱的,也就是說,當i < max時,P[i] >= P[j]一定是成立的;如果i >= max,則無法根據i之前的來確定i的對稱關係,所以初始化,P[i] = 1;然後以i爲中心點,左右延伸,直到不對稱爲止;

   最後,求解完所有P[i]後,遍歷找到最大的P[i]及下標i,那麼在原串中該最大點的起始位置爲(i - P[i]) / 2, 以該點爲起點的最大回文串長度爲P[i] - 1;

class Solution {
public:
    //DP實現, F[i]表示以i爲中心向左/右能夠移動的最大距離, 維護一個當前最大中心點id,以及最大中心點能夠到達的右邊界mx
    //爲了統一處理奇偶問題,給原字符串添加特定的字符,使得字符串永遠以奇數的方式處理,爲了處理邊界問題,增加兩個哨兵
    void preprocess(string s, int n, string &newStr)
    {
        newStr.push_back('$');
        newStr.push_back('#');
        for(int i = 0; i < n; ++i)
        {
            newStr.push_back(s[i]);
            newStr.push_back('#');
        }
        newStr.push_back('^');
    }
    
    string longestPalindrome(string s) {
        int len = s.size();
        string maxStr = s;
        if(len > 1)
        {
            string newStr = "";
            preprocess(s, len, newStr);
            len = newStr.size();
            int *F = new int[len + 3];
            for(int i = 0; i < len + 3; ++i)
                F[i] = 0;
            int id = 0, max = 0;
            for(int i = 1; i < len - 1; ++i)
            {
                F[i] = (max > i) ? min(F[2 * id - i], max - i) : 1;
                while(newStr[i - F[i]] == newStr[i + F[i]]) ++F[i];
                if(i + F[i] > max)
                {
                    id = i;
                    max = i + F[i];
                }
            }
            
            max = -1;
            int maxIndex = 0;
            for(int i = 1; i < len - 1; ++i)
            {
                if(max < F[i])
                {
                    max = F[i];
                    maxIndex = i;
                }
            }
            
            maxStr = s.substr((maxIndex - max) / 2, max - 1);
        }
        
        return maxStr;
    }
};

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