动态规划问题——最长公共子序列问题

题目:

给定两个字符串 str1 和 str2 ,返回两个字符串的最长公共子序列。

举例:

str1 = "1A2C3D4B56"  str2 = "B1D23CA45B6A"

最长公共子序列为:"123456" 或 "12C4B6" 返回哪个都行

思路:

1. 生成 M*N的矩阵dp

动态规划问题——最长公共子序列问题_第1张图片

 代码实现:

    public static int[][] getdp(char[] str1, char[] str2) {
        int[][] dp = new int[str1.length][str2.length];
        dp[0][0] = str1[0] == str2[0] ? 1 : 0;
        //初始化第一列
        for (int i = 1; i < str1.length; i++) {
            dp[i][0] = Math.max(dp[i-1][0],str1[i] == str2[0] ? 1 : 0);
        }
        //初始化第一行
        for (int j = 1; j < str2.length; j++) {
            dp[0][j] = Math.max(dp[0][j-1], str1[0] == str2[j] ? 1 : 0);
        }
        //填充其他位置
        for (int i =1; i < str1.length; i++) {
            for (int j = 1; j < str2.length; j++) {
                dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
                if (str1[i] == str2[j]) {
                    dp[i][j] = Math.max(dp[i][j], dp[i-1][j-1]+1);
                }
            }
        }
        return dp;
    }

测试代码:

    public static void main(String[] args) {

        char[] str1 = "1A2C3D4B56".toCharArray();
        char[] str2 = "B1D23CA45B6A".toCharArray();
        int[][] dp = getdp(str1, str2);
        System.out.println(Arrays.deepToString(dp));
}

测试结果:

动态规划问题——最长公共子序列问题_第2张图片

2. 从dp中拿到最长公共子序列

dp 矩阵中最右下角的值代表str1整体和str2整体的最长公共子序列的长度。

从矩阵的右下角开始,有三种移动方式,向上、向左、向右。

(1)如果 dp[i][j] > dp[i][j-1] 和 dp[i-1][j] ,说明之前在计算 dp[i][j] 的时候,选择了 dp[i-1][j-1]+1这个位置。这就说明 str1[i] 等于 str2[j]。这个字符一定属于最长公共子序列,放入 res。

(2)如果 dp[i][j] 等于 dp[i-1][j] 向上移动。

(3)如果 dp[i][j] 等于 dp[i][j-1] 向左移动。

代码实现:

    public static String lcse(String str1, String str2) {
        if (str1 == null || str2 == null || str1.equals("") || str2.equals("")) {
            return "";
        }
        //将string转换为char数组
        char[] chs1 = str1.toCharArray();
        char[] chs2 = str2.toCharArray();
        int[][] dp = getdp(chs1, chs2);
        int M = chs1.length-1;
        int N = chs2.length-1;
        //拿到 dp矩阵的最右下角的元素
        char[] res = new char[dp[M][N]];
        //index 从末尾开始
        int index = res.length - 1;
        while (index >= 0) {
            //向左移
            if (N > 0 && dp[M][N] == dp[M][N-1]) {
                N--;
            //向上移
            } else if (M > 0 && dp[M][N] == dp[M-1][N]) {
                M--;
            } else {
                res[index] = chs1[M];
                index--;
                M--;
                N--;
            }
        }
        return String.valueOf(res);
    }

动态规划问题——最长公共子序列问题_第3张图片

 

你可能感兴趣的:(算法与数据结构,java,动态规划,算法)