算法: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 ] = { 0   i = 0 ,    j = 0 c [ i − 1 ] [ j − 1 ] + 1   i > 0 , j > 0 ; s t r _ x [ i ] = s t r _ y [ j ] max ⁡ ( c [ i ] [ j − 1 ] ,   c [ i − 1 ] [ j ] )   i > 0 , j > 0 ; s t r _ x [ i ] ≠ s t r _ y [ j ] c[i][j] = \begin{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] \ne str\_y[j] \end{cases} c[i][j]=0c[i1][j1]+1max(c[i][j1], c[i1][j]) i=0,  j=0 i>0,j>0;str_x[i]=str_y[j] i>0,j>0;str_x[i]=str_y[j]
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('\n');

        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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值