zoukankan      html  css  js  c++  java
  • 算法:Common Subsequence(动态规划 Java 最长子序列)

    Description

    A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, ..., xm > another sequence Z = < z1, z2, ..., zk > is a subsequence of X if there exists a strictly increasing sequence < i1, i2, ..., ik > of indices of X such that for all j = 1,2,...,k, xij = zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c, f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.

    Input

    The program input is from the std input. Each data set in the input contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct.

    Output

    For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.

    Sample Input

    abcfbc         abfcab
    programming    contest 
    abcd           mnp
    

    Sample Output

    4
    2
    0
    

    Common Subsequence

    求最大子序列的问题:

    递推关系:c[][]存储最长子序列长度

    $$ c[i][j] = egin{cases} 0 & i = 0, j = 0 \ c[i - 1][j - 1] + 1 & i > 0, j > 0; str\_x[i] = str\_y[j] \ max ( c[i][j - 1], c[i - 1][j] ) & i > 0, j > 0; str\_x[i] e str\_y[j] end{cases} $$

    AC代码:

    import java.util.Scanner;
    
    public class Main {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            String str1, str2;
            while (sc.hasNext()){
                str1 = sc.next();
                str2 = sc.next();
                System.out.println(LcsLength(str1.toCharArray(), str2.toCharArray()));
            }
            sc.close();
        }
    
        public static int LcsLength(char a[], char b[]){
            int aL = a.length;
            int bL = b.length;
            int ans[][] = new int[aL + 1][bL + 1];
            for (int i = 0; i <= aL; i++) {
                ans[i][0] = 0;
            }
            for (int i = 0; i <= bL; i++) {
                ans[0][i] = 0;
            }
            for (int i = 1; i <= aL; i++) {
                for (int j = 1; j <= bL; j++) {
                    if (a[i - 1] == b[j - 1])
                        ans[i][j] = ans[i - 1][j - 1] + 1;
                    else if (ans[i][j - 1] >= ans[i - 1][j])
                        ans[i][j] = ans[i][j - 1];
                    else
                        ans[i][j] = ans[i - 1][j];
                }
            }
            return ans[aL][bL];
        }
    }
    

    可以输出最长子序列之一的代码:

    import java.util.Scanner;
    
    public class Main {
    
        public static int x[][];
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            String str1, str2;
            while (sc.hasNext()) {
                str1 = sc.next();
                str2 = sc.next();
                System.out.println("最大子序列长度: " + LcsLength(str1.toCharArray(), str2.toCharArray()));
            }
            sc.close();
        }
    
        public static int LcsLength(char a[], char b[]) {
            int aL = a.length;      // a数组的长度
            int bL = b.length;      // b数组的长度
            int ans[][] = new int[aL + 1][bL + 1];  // 存储i,j当前的最长子序列长度
            x = new int[aL + 1][bL + 1];            // 存储ans[i][j]是斜对角还是左边,上边来的
            for (int i = 0; i <= aL; i++) {
                ans[i][0] = 0;          // 空的子序列都为0
            }
            for (int i = 0; i <= bL; i++) {
                ans[0][i] = 0;          // 空的子序列都为0
            }
            for (int i = 1; i <= aL; i++) {
                for (int j = 1; j <= bL; j++) {
                    if (a[i - 1] == b[j - 1]) {  // 判断字符是否相等
                        ans[i][j] = ans[i - 1][j - 1] + 1;  // 相等长度加1
                        x[i][j] = 1;            // 标记为相等斜着来的
                    } else if (ans[i][j - 1] >= ans[i - 1][j]) { // 左边大于上边就用最大的
                        ans[i][j] = ans[i][j - 1];
                        x[i][j] = 2;            // 标记为左边来的
                    } else {
                        ans[i][j] = ans[i - 1][j];
                        x[i][j] = 3;            // 标记为上边来的
                    }
                }
            }
            System.out.print("最大子序列: ");
            Lcs(aL, bL, a);
            System.out.print('
    ');
    
            return ans[aL][bL];
        }
    // 递归输出最大子序列其中一个
        public static void Lcs(int i, int j, char a[]) {
            if (i == 0 || j == 0)
                return;
            if (x[i][j] == 1) {
                Lcs(i - 1, j - 1, a);
                System.out.print(a[i - 1]);
            } else if (x[i][j] == 2)
                Lcs(i, j - 1, a);
            else if (x[i][j] == 3)
                Lcs(i - 1, j, a);
        }
    }
    
  • 相关阅读:
    用户场景分析
    团队项目个人工作总结(4月22日)
    团队项目个人工作总结(4月21日)
    团队项目个人工作总结(4月20日)
    第九周学习进度情况
    站立会议10-个人总结
    站立会议9-个人总结
    站立会议8-个人总结
    textarea中文提交乱码问题解决
    站立会议7-个人总结
  • 原文地址:https://www.cnblogs.com/yanhua-tj/p/13996567.html
Copyright © 2011-2022 走看看