• 动态规划之最长公共子序列


    问题引入

    有两个串S1和S2,寻找第三个串S3,要求S3的所有内容都出现在S1和S2中,且在三个串中出现的顺序相同,但在S1和S2中不要求连续出现。

    S3称为S1和S2的最长公共子序列(LCS)。

    求解方案

    在求X=<x1,x2,x3,...,xm>和Y=<y1,y2,y3,...yn>的一个Lcs时,需要求解一个或两个子问题:
    1.如果xm = yn,就应该求解xm-1和yn-1的一个LCS。将xm和yn追加到这个Lcs上,就得到X和Y的Lcs
    2.如果xm!=yn,则要求解两个子问题:求Xm-1和Y的一个Lcs与X和Yn-1的一个Lcs。两个Lcs中的较长者即为X和Y的一个Lcs。

    很明显,上述求解方式满足动态规划的两个条件:最优子结构和子问题重叠

    自底向上的动态规划求解

    public class LongestCommonSubsequence {
        public static void main(String[] args) {
            String X = "ABCBDAB";
            String Y = "BDCABA";
            char[][] b = lcs(X,Y);
            char[] x = X.toCharArray();
            printLcs(b,x,X.length(),Y.length());
        }
        //动态规划自底向上计算
        static char[][] lcs(String X, String Y){
            char[] x = X.toCharArray();
            char[] y = Y.toCharArray();
            int m = x.length, n = y.length;
            char[][] b = new char[m][n];
            int[][] c = new int[m+1][n+1];
            //初始化c的第一行和第一列为0
            for (int i = 0;i <= m;i++){
                c[i][0] = 0;
            }
            for (int j = 0;j <= n;j++){
                c[0][j] = 0;
            }
    
            for (int i = 1;i <= m;i++){
                for (int j = 1;j <=n;j++){
                    //如果比较结果相等,则c[i][j]为x[i-1]和y[j-1]最长公共子序列长度+1
                    if (x[i-1] == y[j-1]){
                        c[i][j] = c[i-1][j-1]+1;
                        b[i-1][j-1] = '↖';
                    //结果不等,则c[i][j]取 x[i]与y[j-1]的最长公共子序列 和 x[i-1]与y[j]的最长公共子序列 中的较大者
                    }else if (c[i-1][j] >= c[i][j-1]){
                        c[i][j] = c[i-1][j];
                        b[i-1][j-1] = '↑';
                    }else {
                        c[i][j] = c[i][j-1];
                        b[i-1][j-1] = '←';
                    }
                }
            }
            for (int i = 0;i < m+1;i++){
                for (int j = 0;j < n+1;j++){
                    System.out.print(c[i][j]);
                }
                System.out.println();
            }
            for (int i = 0;i < m;i++){
                for (int j = 0;j < n;j++){
                    System.out.print(b[i][j]);
                }
                System.out.println();
            }
            return b;
        }
        //b为lcs得到的二维数组;x为其中一个字符串(转换为字符数组);m,n分别为两个字符串的长度
        static void printLcs(char[][] b,char[] x,int m,int n){
            if (m == 0 || n == 0){
                return;
            }
            //b[m-1][n-1]=='↖'对应的是x[m-1]和y[n-1]相等,于是递归调用printLcs从b[m-2][n-2]判断
            if (b[m-1][n-1] == '↖'){
                printLcs(b,x,m-1,n-1);
                System.out.print(x[m-1]);
            //x[m-1]和y[n-1]不等,递归调用printLcs从b[m-2][n-1]判断,因为b[m-1][n-1] == '↑'表示
            //x[i]与y[j-1]的最长公共子序列 和 x[i-1]与y[j]的最长公共子序列 中的较大者为后者
            }else if (b[m-1][n-1] == '↑'){
                printLcs(b,x,m-1,n);
            //x[m-1]和y[n-1]不等,递归调用printLcs从b[m-1][n-2]判断,因为b[m-1][n-1] == '←'表示
            //x[i]与y[j-1]的最长公共子序列 和 x[i-1]与y[j]的最长公共子序列 中的较大者为前者
            }else {
                printLcs(b, x, m, n-1);
            }
        }
    }
    
    

    运行结果如下:

  • 相关阅读:
    app ios info权限配置:
    ionic3 小记录
    mipush ionic3 线上push
    ionic3 生命周期 之 ionViewWillLeave 坑
    iphone X 底部留白 之 ionic3 项目
    微信小程序 修改手机状态栏颜色
    git 命令
    微信小程序 下拉加载
    js 判断浏览器型号
    关于 ionic3 tabs 导航ico 点击 页面返回顶部
  • 原文地址:https://www.cnblogs.com/cky-2907183182/p/12206412.html
Copyright © 2020-2023  润新知