用动态规划的方法解决LCS(最长公共子序列)的问题

化为笔试中有这样的题目,如果用递归去做,运行时间为指数函数。用动态规划的方法去做,运行时间为O(mn).
java代码如下:

import java.util.*;

//请忽略类名及对象名,随手一起而而已,并没有什么特殊含义
public class Store{
    public static void main(String[] args){
        Store steel = new Store();
        steel.init_m();
        steel.F(7, 6);

        //--打印出m表,便于分析------------------------------
        System.out.print(" ");
        for(int in = 0;in<6;in++){
            System.out.print(steel.y[in] + " ");
        }
        System.out.println();
        for(int i =1; i < 8; i++){
            System.out.print(steel.x[i-1]+" ");
            for(int j = 1; j < 7; j++){

                System.out.print(steel.m[i][j] + " ");
            }
            System.out.println();
        }
        //--------------------------------------------

        steel.reF(7, 6);

        System.out.println("\n LCS的长度为: " + steel.m[7][6]);
    }

    private char[] x = {'a','b','c','b','d','a','b'};//7
    private char[] y = {'b','d','c','a','b','a'};//6

    private int[][] m = new int[8][7]; //储存子问题的结果

    //初始化m表
    private void init_m(){
        for(int i = 0; i < 8; i++)
                m[i][0]= 0;
        for(int j = 0; j <7; j++)
            m[0][j] = 0;
    }

    //自底向上的动态规划方法 
    private void F(int m, int n){
        //以行为主次序
        for(int i = 1; i <= m; i++){
            for(int j = 1; j <= n; j++){
                //因为x y 是从0开始的,所以才-1. 
                //如果 x y 的第一个元素相等,就把对应的m值+1
                if(x[i-1] == y[j-1]){
                    this.m[i][j] = this.m[i-1][j-1]+1;
                }
                //否则,如果上面的值大于左边的值,把上面的值拿过来
                else if(this.m[i-1][j] >= this.m[i][j-1]){
                    this.m[i][j] = this.m[i-1][j];
                }
                //否则,把下边的值拿过来
                else
                    this.m[i][j] = this.m[i][j-1];

            }
        }
    }

    //用于重构LCS(最长公共子序列),可以对应着打印出来的m表来写这个函数
    private void reF(int i, int j){
        //防止越界
        if(i == 0 || j == 0){
            return ;
        }
        //对应于 F()函数。
        //先考虑上面的值
        if(this.m[i][j] == this.m[i-1][j]){
            reF(i-1, j);
        }
        //再考虑左边的值
        else if(this.m[i][j-1] == this.m[i][j]){
            reF(i, j-1);
        }
        //前面的条件都不满足,那么此处的x[i-1](跟y[j-1]相等)就是我们想要的一个LCS的元素
        else{
            //打印出来的顺序是反着的
            System.out.print(this.x[i-1] + " ");
            reF(i-1, j-1);
        }
    }

}


输出结果:
  b d c a b a 
a 0 0 0 1 1 1 
b 1 1 1 1 2 2 
c 1 1 2 2 2 2 
b 1 1 2 2 3 3 
d 1 2 2 2 3 3 
a 1 2 2 3 3 4 
b 1 2 2 3 4 4 
a b c b 
 LCS的长度为: 4

顺便用递归来解LCS长度问题的算法:

F(int i, int j)
if i == 0 or j == 0
    return 0
if x(i) == y(j)
    m(i,j) = F(i-1, j-1) + 1 //如果两个元素相等,问题就变x的子序列与y的子序列的问题了
else 
    return max(F(i, j-1), F(i-1, j)) //如果两个元素不相等,问题就变成两个子问题

你可能感兴趣的:(用动态规划的方法解决LCS(最长公共子序列)的问题)