最长公共子序列

动态规划合集:

1.矩阵链乘法
2.投资组合问题
3.完全背包问题
4.01背包问题
5.最长公共子序列

例题5——最长公共子序列

描述

给定序列

求X和Y的最长公共子序列。
实例:
X:A B C B D A B
Y:B D C A B A
最长公共子序列为:BCBA,长度为4

问题分析

以做一般性说明,其中Z表示XY的最长公共子序列,一定有下述条件:

①若,且是的LCS。

②若,是与的LCS。

③若是与的LCS。

令表示的LCS的长度,那么递推表达式可以写成:

标记函数为:

16484271-db2d6d2437f8d46d.png
标记函数走法

算法实现

public class LongestCommonSubsequence {
    public static int [][]mem;
    public static int [][]s;
    public static int [] result; // 记录子串下标
    public static int LCS(char []X,char []Y,int n,int m){
        for (int i = 0; i <= n; i++) {
            mem[i][0] = 0;
            s[i][0] = 0;
        }
        for (int i = 0; i <= m; i++) {
            mem[0][i] = 0;
            s[0][i] = 0;
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m ; j++) {
                if (X[i-1] == Y[j-1]){
                    mem[i][j] = mem[i-1][j-1] + 1;
                    s[i][j] = 1;
                }
                else {
                    mem[i][j] = Math.max(mem[i][j-1],mem[i-1][j]);
                    if (mem[i][j] == mem[i-1][j]){
                        s[i][j] = 2;
                    }
                    else s[i][j] = 3;
                }
            }
        }
        return mem[n][m];
    }
    // 追踪解
    public static void trace_solution(int n,int m){
        int i = n;
        int j = m;
        int p = 0;
        while (true){
            if (i== 0 || j == 0) break;
            if (s[i][j] == 1 ){
                result[p] = i;
                p++;
                i--;j--;
            }
            else if (s[i][j] == 2){
                i--;
            }
            else { //s[i][j] == 3
                j--;
            }
        }

    }
    public static void print(int [][]array,int n,int m){
        for (int i = 0; i < n + 1; i++) {
            for (int j = 0; j < m + 1; j++) {
                System.out.printf("%d ",array[i][j]);
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        char []X = {'A','B','C','B','D','A','B'};
        char []Y = {'B','D','C','A','B','A'};
        int n = X.length;
        int m = Y.length;
        // 这里重点理解,相当于多加了第一行 第一列。
        mem = new int[n+1][m+1];
        // 1 表示 左上箭头  2 表示 上  3 表示 左
        s = new int[n+1][m+1];
        result = new int[Math.min(n,m)];
        int longest = LCS(X,Y,n,m);
        System.out.println("备忘录表为:");
        print(mem,n,m);
        System.out.println("标记函数表为:");
        print(s,n,m);
        System.out.printf("longest : %d \n",longest);

        trace_solution(n,m);
        // 输出注意  result 记录的是字符在序列中的下标
        for (int k = longest-1; k >=0 ; k--) {
            // 还需要再减一 才能跟 X Y序列对齐。
            int index = result[k]-1;
            System.out.printf("%c ",X[index]);
        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值