最长公共子序列

Posted runmoxin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最长公共子序列相关的知识,希望对你有一定的参考价值。

题目描述:

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

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

 

问题说明:

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

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

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

 

特点分析:

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

 

数据结构:

  假设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()];
    }
}

 

以上是关于最长公共子序列的主要内容,如果未能解决你的问题,请参考以下文章

最长公共子序列与最长公共字串

最长公共子序列

最长公共子序列

字符串最长公共子序列问题

最长公共子序列

最长公共子序列