最直接的解決方法是:生成給定字符串的所有子序列,並找出最長的迴文序列,這個方法的複雜度是指數級的。下面來分析怎麼用動態規劃解決。
1)最優子結構
假設 X[0 ... n-1] 是給定的序列,長度爲n. 讓 L(0,n-1) 表示 序列 X[0 ... n-1] 的最長迴文子序列的長度。
1. 如果X的最後一個元素和第一個元素是相同的,這時:L(0, n-1) = L(1, n-2) + 2 , 還以 “BBABCBCAB” 爲例,第一個和最後一個相同,因此 L(1,n-2) 就表示藍色的部分。
2. 如果不相同:L(0, n-1) = MAX ( L(1, n-1) , L(0, n-2) )。 以”BABCBCA” 爲例,L(1,n-1)即爲去掉第一個元素的子序列,L(0, n-2)爲去掉最後一個元素。
2)重複子問題
具體實例及實現代碼如下所示:
/** * @Title: LPS.java * @Package dynamicprogramming * @Description: TODO * @author peidong * @date 2017-6-12 上午9:36:55 * @version V1.0 */ package dynamicprogramming; /** * @ClassName: LPS * @Description: 最長迴文子序列 * @date 2017-6-12 上午9:36:55 * */ public class LPS { /** * * @Title: lpsRecursion * @Description: 利用遞歸求解LPS * @param seq 字符串 * @param i 起始位置 * @param j 終止位置 * @return * @return int * @throws */ public static int lpsRecursion(String seq, int i, int j){ //邊界條件,只有一個元素 if(i == j) return 1; if(i > j) return 0; //只計算序列seq[i...j] //如果首尾相同 if(seq.charAt(i) == seq.charAt(j)) return lpsRecursion(seq, i+1, j-1) + 2; //首尾不同 return Math.max(lpsRecursion(seq, i, j-1), lpsRecursion(seq, i+1, j)); } /** * * @Title: lps * @Description:利用動態規劃求解LPS * @param seq * @param n * @return * @return int * @throws */ public static int lps(String seq, int n){ //創建狀態轉移矩陣 int[][] tc = new int[n][n]; int temp; //初始化狀態轉移矩陣 for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ tc[i][j] = 0; } } for(int i = 0; i < n; i++) tc[i][i] = 1; //構建狀態轉移矩陣 for(int i = 1; i < n; i++){ temp = 0; //考慮所有連續的長度爲i+1 的子串 for(int j = 0; j + i < n; j++){ //如果首尾相同 if(seq.charAt(j) == seq.charAt(j+i)) temp = tc[j+1][j+i-1]+2; else temp = Math.max(tc[j+1][j+i], tc[j][j+i-1]); tc[j][j+i] = temp; } } return tc[0][n-1]; } /** * @Title: main * @Description: TODO * @param args * @return void * @throws */ public static void main(String[] args) { // TODO Auto-generated method stub String seq = "acmerandacm"; int n = seq.length(); System.out.println("利用遞歸求解LPS結果:"+ lpsRecursion(seq, 0, n-1)); System.out.println("利用dp求解LPS結果:"+ lps(seq, n)); } }