zoukankan      html  css  js  c++  java
  • 最长公共子序列

    题目描述:

      有两个字符串,求这两个字符串的最长的公共子序列的长度(一般情况下,默认是求公共子序列的长度)。

    在刷题的过程中页有遇到这样的要求:求公共子序列的长度,并输出最长公共子序列。 

    问题说明:

      如下的代码中,虽然成功的输出了公共子序列,但是总感觉有些不足之处。因为在自己编写的两个字符串中,存在长度相同的最长公共子序列。

    带来的问题就是,我们输出的子序列不具有唯一性。在不同的编程题目中,有可能会和最终的结果出现差异。可以调整一下方法中的参数,使用不

    同的字符串作为方法的参数,得到的结果也是不同的。 

    特点分析:

      关于两个字符串的最长公共子序列,特点是子序列的字符在原来的字符串中的顺序是一致的,但是并不要求所有的字符都是连续的。 

    数据结构:

      假设Z是str1和str2的公共子序列

      str1的长度我们用x来表示

      str2的长度我们用y来表示

      建立状态转换矩阵为dp[i][j],用来表示两个字符串的最长公共子序列的长度。

      通过分析题目我们可以得到下面的三个结论:

        当str1下标为i的字符刚好等于str2下标为j的字符dp[i][j] = dp[i -1][j -1] + 1

        当str1的第i个字符和str2的第j个字符不相同的时候,那么dp[i][j] 的值就是dp[i -1][j]和dp[i ][j -1]中最大的那个

      通过记录每次得到公共字符的某种情况,可以反推得到这个字符。

    示例代码如下:

    public class LCSS {
        public static final int THIS = 1;
        public static final int UP = 2;
        public static final int LIFT = 3;
        public static void main(String[] args) {
            String str1 = "abcdcfe";
            String str2 = "abcfedc";
            int len1 = str1.length();
            int len2 = str2.length();
            int[][] dp = new int[len1+1][len2+1];
            int[][] status = new int[len1+1][len2+1];// 保存确定最大公共子序列时的三个状态,方便后续查找出对应的字符
            int res = getLCS(str1,str2,dp,status);
            System.out.println(res);
            print_LCS(len1,len2,str1,status);
        }
    
        private static void print_LCS(int len1,int len2,String str1, int[][] status) {
    
            if (len1 == 0 || len2 == 0){
                return;
            }
            if (status[len1][len2] ==THIS){
                print_LCS(len1-1,len2-1,str1,status);
                System.out.print(str1.charAt(len1-1));
            }else if(status[len1][len2] ==UP){
                print_LCS(len1,len2-1,str1,status);
            }else{
                print_LCS(len1-1,len2,str1,status);
            }
        }
    
        private static int getLCS(String str1, String str2, int[][] dp, int[][] status) {
            for (int i =0;i<=str1.length(); i++){ // 在状态转换矩阵中,第一行的值是已知的.都是0
                dp[i][0] = 0;
                status[i][0] = 0;
            }
            for (int j=0;j<=str2.length(); j++){ // 在状态转换矩阵中,第一列的值是已知的.都是0
                dp[0][j] = 0;
                dp[0][j] = 0;
            }
            for (int i = 1; i<=str1.length(); i++){
                for (int j =1;j<=str2.length();j++){
                    if(str1.charAt(i-1) == str2.charAt(j-1)){
                        dp[i][j] = dp[i-1][j-1]+1;
                        status[i][j] = THIS;
                    }else{
                        if(dp[i-1][j]<=dp[i][j-1]){
                            dp[i][j] = dp[i][j-1];
                            status[i][j] = UP;
                        }else{
                            dp[i][j] = dp[i-1][j];
                            status[i][j] = LIFT;
                        }
                    }
                }
            }
            return dp[str1.length()][str2.length()];
        }
    }
  • 相关阅读:
    希望走过的路成为未来的基石
    第三次个人作业--用例图设计
    第二次结对作业
    第一次结对作业
    第二次个人编程作业
    第一次个人编程作业(更新至2020.02.07)
    Springboot vue 前后分离 跨域 Activiti6 工作流 集成代码生成器 shiro权限
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    spring cloud springboot 框架源码 activiti工作流 前后分离 集成代码生成器
    java代码生成器 快速开发平台 二次开发 外包项目利器 springmvc SSM后台框架源码
  • 原文地址:https://www.cnblogs.com/runmoxin/p/12838792.html
Copyright © 2011-2022 走看看