给定两个序列X,Y,求最长公共子序列。

参考:《算法设计与分析》张德富 g
例如:
  X = { a , b , c , b , d , a , b }
  Y = { b , d , c , a , b , a }
  最长公共子序列为
  LSC = { b , c , b , a }
  
分析:
  最长公共子序列问题具有最优子结构性质
  设X = { x1 , ... , xm } Y = { y1 , ... , yn }
  及它们的最长子序列Z = { z1 , ... , zk }
  则
  1、若 xm = yn , 则 zk = xm = yn,且Z[k-1] 是 X[m-1] 和 Y[n-1] 的最长公共子序列
  2、若 xm != yn ,且 zk != xm , 则 Z 是 X[m-1] 和 Y 的最长公共子序列
  3、若 xm != yn , 且 zk != yn , 则 Z 是 Y[n-1] 和 X 的最长公共子序列
  由性质导出子问题的递归结构:
用c[i,j]表示X[1...i]与Y[1...j]公共子序列长度。
  当 i = 0 or j = 0 时 ,      c[i,j] = 0
  当 i , j > 0 ; xi = yj 时 , c[i,j] = c[i-1,j-1] + 1
  当 i , j > 0 ; xi!= yj 时 , c[i,j] = max { c[i,j-1] , c[i-1,j] }
 
实现:
c[m,n]数组存放公共子序列长度。b[m,n]存放由哪个子问题决定c[i,j]?是c[i-1,j-1],c[i,j-1]还是c[i-1,j].用于最后输出公共子序列。
求公共子序列长度函数dpLCS时间复杂度O(mn),根据结果构造公共子序列genLCS的时间复杂度为O(m+n)
 
 
  
  1. /** 
  2.  * Dynamic Programming, DP 
  3.  * 
  4.  */ 
  5. public class DPLCS { 
  6.  
  7.     /** 
  8.      * @param args 
  9.      */ 
  10.     public static void main(String[] args) { 
  11.         // TODO Auto-generated method stub 
  12.         String x = "abcbdab"
  13.         String y = "bdcaba"
  14.         String cls = "bdab"
  15.         DPLCS dp = new DPLCS(x.toCharArray(),y.toCharArray()); 
  16.         System.out.println(dp.getDPLCSLength()); 
  17.         System.out.println(dp.getDPLCS()); 
  18.     } 
  19.      
  20.     private int[][] c = null
  21.     private int[][] b = null
  22.     private char[] x = null
  23.     private char[] y = null
  24.     private int lcsLength; 
  25.     private char[] lcs; 
  26.      
  27.     public DPLCS(char[] x, char[] y, int m, int n){ 
  28.         c = new int[m+1][n+1]; 
  29.         b = new int[m+1][n+1]; 
  30.         for (int i = 0; i < m+1; i++) c[i][0]=0
  31.         for (int j = 0; j < n+1; j++) c[0][j]=0
  32.         this.x = x; 
  33.         this.y = y; 
  34.         dpLcs(x, y, m, n);       
  35.         lcs = new char[lcsLength]; 
  36.         //生成公共子序列 
  37.         genLCS(m, n, lcsLength-1); 
  38.     } 
  39.     public DPLCS(char[] x, char[] y){ 
  40.         this(x, y, x.length, y.length); 
  41.     } 
  42.      
  43.     private void dpLCS(char[] x, char[] y, int m, int n) { 
  44.         // TODO Auto-generated method stub 
  45.         for (int i = 1; i < m+1; i++) { 
  46.             for (int j = 1; j < n+1; j++) { 
  47.                 if(x[i-1]==y[j-1]){//注意index 
  48.                     c[i][j]=c[i-1][j-1]+1
  49.                     b[i][j]=1;//表示由子问题i-1,j-1得来 
  50.                 }else
  51.                     if(c[i][j-1]>=c[i-1][j]){ 
  52.                         c[i][j]=c[i][j-1]; 
  53.                         b[i][j]=2;//表示由子问题i,j-1得来 
  54.                     } 
  55.                     else
  56.                         c[i][j]=c[i-1][j]; 
  57.                         b[i][j]=3;//表示由子问题i-1,j得来 
  58.                     } 
  59.                 } 
  60.             } 
  61.         } 
  62.         lcsLength = c[m][n]; 
  63.     }    
  64.  
  65.     private void genLCS(int i, int j, int index) { 
  66.         // TODO Auto-generated method stub 
  67.         if(index<0
  68.             return
  69.         if(b[i][j]==1){ 
  70.             lcs[index]= x[i-1]; 
  71.             genLCS(i-1,j-1,index-1); 
  72.         } 
  73.         else if(b[i][j]==2
  74.             genLCS(i,j-1,index); 
  75.         else 
  76.             genLCS(i-1,j,index); 
  77.     } 
  78.      
  79.     public int getDPLCSLength(){ 
  80.         return lcsLength; 
  81.     } 
  82.     public char[] getDPLCS(){ 
  83.         return lcs; 
  84.     } 

缺陷:最长公共子序列可能有多条,该程序只求出其中一条