最长公共子序列--动态规划算法

时间:2021-05-03 18:40:39

考虑最长公共子序列问题如何分解成子问题,设A=“a0,a1,…,am-1”,B=“b0,b1,…,bn-1”,并Z=“z0,z1,…,zk-1”为它们的最长公共子序列。不难证明有以下性质:

(1) 如果am-1=bn-1,则zk-1=am-1=bn-1,且“z0,z1,…,zk-2”是“a0,a1,…,am-2”和“b0,b1,…,bn-2”的一个最长公共子序列;

(2) 如果am-1!=bn-1,则若zk-1!=am-1,蕴涵“z0,z1,…,zk-1”是“a0,a1,…,am-2”和“b0,b1,…,bn-1”的一个最长公共子序列;

(3) 如果am-1!=bn-1,则若zk-1!=bn-1,蕴涵“z0,z1,…,zk-1”是“a0,a1,…,am-1”和“b0,b1,…,bn-2”的一个最长公共子序列。

问题的递归式写成:

 

 

最长公共子序列--动态规划算法

回溯输出最长公共子序列过程:

最长公共子序列--动态规划算法

package test;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: LCS
 * @Description: TODO
 * @author:
 * @Date: 2015-06-29 12:50:14
 */
public class LCS {

    static int MAX=2;
    
    public static List<String> getLCS(int[][] c, int i, int j, String x, String y){
        List<String> t = new ArrayList<String>();
        if(i == 0 || j == 0){
            ;
        }else if(c[i][j] == 1){
            t = getLCS(c,i-1,j-1,x,y);
            if(t.size() == 0)
                t.add("");
            for(int k = 0; k < t.size(); k++){
                String v = t.get(k);
                if(v.length() > 0){
                    int it = Integer.parseInt(v.substring(v.lastIndexOf("(")+1,v.lastIndexOf(",")));
                    if(i - it > 2){
                        t.remove(k);
                        continue;
                    }
                    int jt = Integer.parseInt(v.substring(v.lastIndexOf(",")+1,v.lastIndexOf(")")));
                    if(j - jt > 2){
                        t.remove(k);
                        continue;
                    }
                }
                t.set(k, t.get(k) + x.charAt(i)+"("+i+","+j+")");
            }
        }else if(c[i][j] == 2){
            t = getLCS(c,i-1,j,x,y);
        }else if(c[i][j] == 3){
            t.addAll(getLCS(c,i-1,j,x,y));
            t.addAll(getLCS(c,i,j-1,x,y));
        }else{
            t = getLCS(c,i,j-1,x,y);
        }
        return t;
    }
    
    public static int LCSLength(int[][] c, int i, int j, byte[] xx, byte[] yy,int[][] max){
        
        if(i == 0 || j == 0){
            c[i][j] = 0;
        }else if(xx[i] == yy[j]){
            max[i][j] = 1;    
            c[i][j] = LCSLength(c,i-1,j-1,xx,yy,max)+1;
        }else {
            int ii = LCSLength(c,i-1,j,xx,yy,max);
            int jj = LCSLength(c,i,j-1,xx,yy,max);
            if(ii > jj)
                max[i][j] = 2;
            else if(ii == jj)
                max[i][j] = 3;
                
            c[i][j] = Math.max(ii,jj);
        }
        return c[i][j];
    }
    
    
    public static void main(String[] args){
        String x = " ABCBDAB";
        String y = " BDCABA";
        
        byte[] xx = x.getBytes();
        byte[] yy = y.getBytes();
        
        int c[][] = new int[x.length()][y.length()];
        int max[][] = new int[x.length()][y.length()];
        System.out.println(LCSLength(c,x.length()-1,y.length()-1,xx,yy,max));
        
        List<String> list  = getLCS(max,x.length()-1,y.length()-1,x,y);
        for(String v: list)
            System.out.println(v);
        System.out.print("\n  ");
        for(int j = 1; j < y.length();j++)
            System.out.print(y.charAt(j)+ " ");
        System.out.println("");
        for(int i = 1; i < x.length(); i++){
            System.out.print(x.charAt(i)+ " ");
            for(int j = 1; j < y.length();j++)
                System.out.print(c[i][j]+ " ");
            System.out.println(" ");
        }
        
    }
}