输出最长公共子序列的长度+打印所有的最长公共子序列+动态规划+java

图文详解动态规划原理——链接

相关概念
子序列形式化定义:
给定一个序列X=,另一个序列Z=,若存在一个严格递增的X的下标序列对所有的1,2,3,...,k,都满足x(ik)=zk,则称Z是X的子序列

比如Z=是X=的子序列

公共子序列定义:
如果Z既是X的子序列,又是Y的子序列,则称Z为X和Y的公共子序列

最长公共子序列(以下简称LCS):
2个序列的子序列中长度最长的那个

动态规划求解最长公共子序列:
分析规律:
设X=,Y=为两个序列,Z=是他们的任意公共子序列

经过分析,我们可以知道:

1、如果xm = yn,则zk = xm = yn 且 Zk-1是Xm-1和Yn-1的一个LCS

2、如果xm != yn 且 zk != xm,则Z是Xm-1和Y的一个LCS

3、如果xm != yn 且 zk != yn,则Z是X和Yn-1的一个LCS

所以如果用一个二维数组c表示字符串X和Y中对应的前i,前j个字符的LCS的长度话,可以得到以下公式:

dp[i][j]的意思表示的是numA以i结尾,numB以j结尾的最长子序列的长度,那么dp[0][i]j就是表示numA[0]和numB以i结尾的最长子序列的长度,所以如果相等时就是1,不等时是0

最长公共子序列的       长度 + 输出所有的最长公共子序列

import java.util.Scanner;
import java.util.TreeSet;

public class Main04_1 {
    public static void main(String [] args){
        Scanner sc = new Scanner(System.in);

        String str1 = sc.nextLine();
        String str2 = sc.nextLine();
        char [] numsA = str1.toCharArray();
        char [] numsB = str2.toCharArray();
        int [][] dp = getMaxLCSLength2(numsA, numsB);
        int len = dp[numsA.length][numsB.length];
        String lcs_str = "";
        traceBack(dp, numsA, numsB, numsA.length,numsB.length,lcs_str);
        System.out.println(len);
    }

    //求最长公共子序列的长度,
    public static int[][] getMaxLCSLength2(char [] arr1, char [] arr2){
        int len1 = arr1.length;
        int len2 = arr2.length;
        int [][] dp = new int[len1+1][len2+1];//此处的动态规划数组长度要比原长度多加1,需要多存储一行0和一列0
        for(int i = 0;i<=len2;i++){第0行第i列全部赋值为0   //这里是<=号
            dp[0][i] = 0;
        }
        for(int i = 0;i<=len1;i++){//第i行,第0列全部为0    //这里是<=号
            dp[i][0] = 0;
        }
        for(int i = 1;i<=len1;i++){//这里是<=号
            for(int j = 1;j<=len2;j++){//这里是<=号
                if(arr1[i-1] == arr2[j-1]){//注意这里若是arr1[i] == arr2[j],就会发生数组越界
                    dp[i][j] = dp[i-1][j-1] + 1;
                }else {
                    dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
                }
            }
        }
        //return dp[len1][len2];
        return dp;
    }

     //功能:回溯,求出所有的最长公共子序列,并放入set中
    public static void traceBack(int [][] dp, char [] arr1, char [] arr2, int i, int j, String lcs_str) {
        TreeSet set = new TreeSet();
        while (i>0 && j>0) {
            if (arr1[i-1] == arr2[j-1]) {
                lcs_str += arr1[i-1];
                i--;
                j--;
            }
            else {
                if (dp[i][j-1]>dp[i-1][j])
                    j--;
                else if (dp[i][j-1]

运行结果
 

abcbdab
bdcaba
bcba
bcab
bdab
4

 

你可能感兴趣的:(算法)