LeetCode5. Longest Palindromic Substring 最長子迴文串

最長子迴文串

5. 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.

Example 1:

Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.

Example 2:

Input: "cbbd"
Output: "bb"
動態規劃

如果一個字符串爲迴文串,那麼除去他的首尾一個字符,得到的新字符依舊是迴文串。即對於一個字符串S有

p(i,j) = p(i+1,j-1) and Si = Sj。P(i,j)表示從i到j的字符串。

從表達式可以看出,需要知道p(i,j),必須先知道p(i+1,j-1)。不如將外層循環倒置過來,先求i+1的值,再求j-1的值。

還有一點要注意的是初始值,關於j - i < 3。如果長度爲1的話,那麼這個字符串必然爲迴文串,如果長度爲2的話,又滿足Si = Sj 那麼他也必然是迴文串。即他們不受上述表達式的約束。

public String longestPalindrome(String s) {
    if(s == null || s.length() < 1){
        return "";
    }
    int len = s.length();
    boolean[][] dp = new boolean[len][len];
    int subLength = 0;
    String res = null;
    for(int i = len - 1; i>= 0 ;i--){
        for(int j = i; j < len; j++){
            dp[i][j] = s.charAt(i) == s.charAt(j) &&(j - i < 3 || dp[i+1][j-1]);
            
            if(dp[i][j] && (res == null || j - i + 1 > res.length())){
                res = s.substring(i,j+1);
            }
        }
    }
    return res;
}
中心擴展算法

首先先看一下回文串有什麼特點,迴文串的最大特點就是中心對齊。如“ababa",他是以a爲中心對齊。那麼對於“abba”這種偶數的迴文串,同樣也是中心對齊的。他以兩個b之間的字符之間爲中心。因此我們可以以數組的每一個元素作爲中心,找出最大的迴文串。

我們可以設置迴文串的頭尾指針,start 和 end。如果有比目前的迴文串更長的迴文串,則修改start和end的的位置。這樣子時間複雜度爲O(n^2),空間複雜度爲O(n)。

public String longestPalindrome(String s) {
    if(s == null || s.length() < 1){
        return "";
    }
    int sLen = s.length();
    int start = 0,end = 0;
    for(int i = 0; i < sLen; i++){
        int len1 = expandAroundCenter(s,i,i);
        int len2 = expandAroundCenter(s,i,i+1);
        int len = Math.max(len1,len2);
        if(len > end - start){
            start = i - (len - 1)/2;
            end = i + len/2;
        }
    }
    return s.substring(start,end+1);
}

private int expandAroundCenter(String s,int left,int right){
    int L = left,R = right;
    while(L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)){
        L--;
        R++;
    }
    return R - L -1;
}
馬拉車算法(Manacher’s Algorithm)

馬拉車算法充分應用了迴文串的對稱性。和中心擴展法一樣,我們以某個節點爲中心,分別向兩邊擴展。爲了保持字符的個數爲奇數,在字符與字符之間插入特殊符號“#”來保證出力的字符個數是爲奇數的。如“abab”變爲“#a#b#a#b#”。假設新的字符串爲T,我們使用P[i] 表示 T[i]處的迴文半徑。如以T[i]爲中心的最長迴文串爲T[l,r],則P[i] = r - i + 1。這樣求最長迴文串的問題就轉換爲求數組P的問題了。

數組P怎麼求,考慮。center 表示之前取得最大回文串的中心位置。right表示最大回文串能到達的最右端的值。

  1. 若i<right,則i之前的值必然計算出來了。我們可以利用迴文串的性質。找出點i關於center的對稱點j。j = 2* center - i。
    1. 如果P[j] < right -i。即以j爲中心的迴文串沒有超出[left,right]的範圍,由迴文串的性質知道,兩端的對應字符應該是相等的。所以有P[j] = P[i]。
    2. 如果P[j] >= right -i。即表明以j爲中心的最大回文串超出了範圍。在範圍內的部分肯定是複合迴文串的性質,但是對於超出的部分,只要從right+1開始一一匹配,從而更新right和對應的center,
  2. 若i > right 無法利用迴文串的性質,只能一步一步去匹配。
 public String longestPalindrome(String s) {
        if(s == null || s.length() < 1){
            return s;
        }
        int sLen = s.length();
        StringBuilder t = new StringBuilder();
        // t.append("$");
        t.append("#");
        for(int i = 0; i < sLen; i++){
            t.append(s.charAt(i));
            t.append("#");
        } 
     
        int tLen = t.length();
        int center = 0;
        int right = 0;
        int maxCenter =0;
        int maxLen = 1;
        
        int[] p = new int[2 *sLen + 1];
        for(int i = 0; i < tLen; ++i){
            
            p[i] = i<right?Math.min(p[2*center -i],right -i):1;
            
            while(i - p[i] >= 0 && i + p[i]<tLen && t.charAt(i - p[i]) == t.charAt(i + p[i])){
                p[i]++;
                
            }
            
            if(right < i + p[i]){
                right = i + p[i];
                center = i;
            }
            
            if(maxLen < p[i]){
                maxLen = p[i];
                maxCenter = i;
            }
            
        }        
        return s.substring((maxCenter - maxLen + 1)/2,(maxCenter - maxLen + 1)/2 + maxLen - 1);
    }
發佈了37 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章