動態規劃之最長迴文子串

問題:給出一個字符串S,求S的最長迴文子串的長度。

結果:字符串"PATZJUJZTACCBCC"的最長迴文子串爲"ATZJUJZTA",長度爲9。

暴力解法

枚舉子串的兩個端點i和j,判斷在[i, j]區間內的子串是否迴文。從複雜度上來看,枚舉端點需要0(n2),判斷迴文需要0(n),因此總複雜度是O(n3)。
        
動態規劃解決
        令dp[i][j]表示S[i]至S[j]所表示的子串是否是迴文子串,是則爲1,不是爲0。這樣根據S[i]是否等於S[j],可以把轉移情況分爲兩類:
         ①若S[i]=S[j],那麼只要S[i+1]和S[j-1]是迴文子串,S[i]至S[j]就是迴文子串;如果S[i+1]至S[j-1]不是迴文子串,則S[i]至S[j]一定不是迴文子串。
         ②若S[i]!=S[j],那S[i]至S[j]一定不是迴文子串。
由此可以寫出狀態轉移方程
 

邊界dp[i][i]=1,dp[i][i+1]=(S[i]==S[i+1])?1:0 。

到這裏還有一個問題沒有解決,那就是如果按照i和j從小到大的順序來枚舉子串的兩個端點,然後更新dp[i]lj],會無法保證dp[i + 1][j - 1]已經被計算過,從而無法得到正確的dp[i][i]。
         如圖11-4所示,先固定i=0,然後枚舉j從2開始。當求解dp[0][2]時,將會轉換爲dp[1][1],而dp[1][1]是在初始化中得到的;當求解dp[0][3]時,將會轉換爲dp[1][2], 而dp[1][2]也是在初始化中得到的;當求解dp[0][4]時,將會轉換爲dp[1][3], 但是dp[1][3]並不是已經計算過的值,因此無法狀態轉移。事實上,無論對i和j的枚舉順序做何調整,都無法調和這個矛盾,因此必須想辦法尋找新的枚舉方式。
        根據遞推寫法從邊界出發的原理,注意到邊界表示的是長度爲1和2的子串,且每次轉移時都對子串的長度減了1,因此不妨考慮按子串的長度和子串的初始位置進行枚舉,即第一遍將長度爲3的子串的dp值全部求出,第二遍通過第一遍結果計算出長度爲4的子串的dp值…這樣就可以避免狀態無法轉移的問題。如圖11-5所示,可以先枚舉子串長度L (注意: L是可以取到整個字符串的長度S.len()的),再枚舉左端點i,這樣右端點i+ L- 1也可以直接得到。


public class Solution {

  public static void main(String[] args) {
    maxSubMirrorString("PATZJUJZTACCBCC");
  }

  public static void maxSubMirrorString(String str) {
    char[] chars = str.toCharArray();
    int length = chars.length;
    int dp[][] = new int[length][length];
    int maxSubMirrorStrLength = 1;

    //初始化dp[i][i],dp[i][i+1]
    for (int i = 0; i < length; i++) {
      dp[i][i] = 1;
      if (i < length - 1) {
        if (chars[i] == chars[i + 1]) {
          dp[i][i + 1] = 1;
          maxSubMirrorStrLength = 2;
        }
      }
    }

    //狀態轉移方程
    for (int L = 3; L <= length; L++) {//枚舉子串長度
      //枚舉子串起始端點 起始端點加上子串長度(子串長度包括他本身,所以要-1)必須小於總長
      int j;//子串右端點
      for (int i = 0; (j = i + L - 1) < length; i++) {
        if (chars[i] == chars[j] && dp[i + 1][j - 1] == 1) {
          dp[i][j] = 1;
          maxSubMirrorStrLength = L;//更新最長迴文子串長度;
        }
      }
    }

    System.out.println("最長迴文子串長度:" + maxSubMirrorStrLength);
  }
}

 

 

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