LeetCode 第 1143 题:最长公共子序列(动态规划)

地址:https://leetcode-cn.com/problems/longest-common-subsequence/

这里要为了考虑清楚边界问题,需要设置一个特殊的状态 0,这是基于特殊用例一个非空字符串与空字符串而来的。

  • 状态定义:dp[i][j] 表示长度为 itext1前缀子串与长度为 jtext2 的前缀子串的“最长公共子串”的长度。

(类似的定义方式还有「力扣」第 10 题:正则表达式。)

  • 状态转移方程:

dp [ i ] [ j ] = { dp [ i − 1 ] [ j − 1 ] if text1 [ i ] = text2 [ j ] dp [ i ] [ j − 1 ] dp [ i − 1 ] [ j ] \text{dp}[i][j] = \begin{cases} \text{dp}[i - 1][j - 1] &\text{if} \ \text{text1}[i] = \text{text2}[j] \\ \text{dp}[i][j - 1] \\ \text{dp}[i - 1][j] \end{cases} dp[i][j]=dp[i1][j1]dp[i][j1]dp[i1][j]if text1[i]=text2[j]

  • 初始化:表格 dp 的第 1 行和第 1 列均为 0。
  • 输出:dp[len1][len2]

Java 代码:

public class Solution {

    public int longestCommonSubsequence(String text1, String text2) {
        int len1 = text1.length();
        int len2 = text2.length();

        int[][] dp = new int[len1 + 1][len2 + 1];
        for (int i = 0; i <= len1; i++) {
            dp[i][0] = 0;
        }
        for (int j = 0; j <= len2; j++) {
            dp[0][j] = 0;
        }
        for (int i = 0; i < len1; i++) {
            for (int j = 0; j < len2; j++) {
                if (text1.charAt(i) == text2.charAt(j)) {
                    dp[i + 1][j + 1] = dp[i][j] + 1;
                } else {
                    dp[i + 1][j + 1] = Math.max(dp[i + 1][j], dp[i][j + 1]);
                }
            }
        }
        return dp[len1][len2];
    }
}

说明:如果不考虑边界,写出来的代码是这样的。可以对比一下,代码量会多一些,而且比较容易出错。

Java 代码:

public class Solution {

    public int longestCommonSubsequence(String text1, String text2) {
        int len1 = text1.length();
        int len2 = text2.length();

        int[][] dp = new int[len1][len2];

        if (text1.charAt(0) == text2.charAt(0)) {
            dp[0][0] = 1;
        }

        // 写第 1 行
        for (int j = 1; j < len2; j++) {
            dp[0][j] = dp[0][j - 1];
            if (text1.charAt(0) == text2.charAt(j)) {
                dp[0][j] = 1;
            }
        }

        // 写第 1 列
        for (int i = 1; i < len1; i++) {
            dp[i][0] = dp[i - 1][0];
            if (text1.charAt(i) == text2.charAt(0)) {
                dp[i][0] = 1;
            }
        }

        for (int i = 1; i < len1; i++) {
            for (int j = 1; j < len2; j++) {
                if (text1.charAt(i) == text2.charAt(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 - 1][len2 - 1];
    }
}
  • 状态压缩。

参考资料:

1、MathJax使用LaTeX语法编写数学公式教程
地址:https://www.zybuluo.com/knight/note/96093

你可能感兴趣的:(力扣)