動態規划---最長公共子序列


1、問題描述
一個給定序列的子序列是在該序列中刪去若干元素后得到的序列。確切的說,若給定序列X={x1,x2,…,xm},則另一序列Z={z1,z2,…,zk},X的子序列是指存在一個嚴格遞增下標序列{i1,i2,…,ik}使得對於所有j=1,2,…k有zj=xij 例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相應的遞增下標序列為{2,3,5,7}.
給定兩個序列X和Y,當另一序列Z既是X的子序列又是Y的子序列時,稱Z是序列X和Y的公共子序列,公共子序列可以有多個,最長公共子序列是X和Y序列的最長的一個.


2、算法描述:
當xm =yn 時,找出Xm-1 和Yn-1 的最長公共子序列,然后在其尾部加上xm (=yn)即可得X和Y的最長公共子序列.當xm !=yn 時,必須解兩個子問題,即找出Xm-1 和Y的一個最長公共子序列及X和Yn-1 的一個最長公共子序列。這兩個公共子序列中較長者即為X和Y的最長公共子序列.

C[i][j]存儲Xi和Yj的最長公共子序列的長度,from[i][j]代表C[i][j]長度所得來源於哪種情況;

3、算法時間復雜性分析
求解公共子序列的長度復雜度為m*n,根據存儲狀態表求子序列並輸出復雜度為m*n,所以最終時間復雜度為m*n;

代碼如下:

import java.util.Scanner;
public class LCS {
    public static void main(String[] args) {
        //ABCDEFGIE
        //BCDFGE
        Scanner input = new Scanner(System.in);
        String as = input.nextLine();
        String bs = input.nextLine();
        char [] a = as.toCharArray();
        char [] b = bs.toCharArray();
        int[][] from = init(a,b);
        comLength(a,b,from);
        //printArray(from);
        printCom(a,from,a.length-1,b.length-1);
    }
    public static void printArray(int[][] from){//輸入給定數組將其打印
        for(int i=0; i<from.length ; i++){
            for(int j=0; j<from[0].length ; j++){
                System.out.print(from[i][j]+" ");
            }
            System.out.println();
        }
    }
    public static int[][] init(char[]a,char[]b){//創建來源數組
        int[][] from = new int[a.length][b.length];
        for(int i=0; i<a.length; i++){
            for(int j=0; j<b.length; j++){
                from[i][j]=0;
            }
        }
        return from;
    }
    public static void comLength(char[]a,char[]b,int[][]from){//為from狀態數組賦值
         int m = a.length;
         int n = b.length;
         int [][]c = new int[m][n];
         for(int i=0; i<m; i++){
             for(int j=0; j<n; j++){
                 c[i][j]=0;
             }
         }
         for(int i=1; i<m; i++){
             for(int j=1; j<n; j++){
                 if(a[i]==b[j]){//代表來源於第1種情況:比較的兩個字符串的最后一位相等
                     c[i][j]=c[i-1][j-1]+1;
                     from[i][j]=1;
                 }else if(c[i][j-1]>=c[i-1][j]){//代表來源於第2種情況:比較的兩個字符串的最后一位相等且最長公共子序列的最后一位不等於a數組字符序列的最后一位;
                     c[i][j]=c[i][j-1];
                     from[i][j]=2;
                 }else{//代表來源於第3種情況:比較的兩個字符串的最后一位不相等且最長公共子序列的最后一位不等於b數組字符序列的最后一位;
                     c[i][j]=c[i-1][j];
                     from[i][j]=3;
                 }
             }
         }
//         printArray(c);
//         System.out.println();
    }
    public static void printCom(char[]a , int[][]from , int m ,int n){//根據from狀態數組輸出最長公共子序列
          if(m==0|n==0)return;
          if(from[m][n]==1){
                 printCom(a,from,m-1,n-1);
                 System.out.print(a[m]);
          }else if(from[m][n]==2){
              printCom(a,from,m,n-1);
          }else {
              printCom(a,from,m-1,n);
          }
    }
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM