day53 ● 1143.最长公共子序列 ● 1035.不相交的线 ● 53. 最大子序和

161 阅读2分钟

本文介绍了如何使用动态规划算法解决三个问题:最长公共子序列(Longest Common Subsequence)、不相交的线(Uncrossed Lines)和最大子序和(Maximum Subarray)。这些问题都是计算机科学中著名的经典问题,它们可以使用动态规划算法高效地解决。

动态规划算法是一种通过将问题分解为子问题,并以递归方式解决子问题来解决问题的方法。在动态规划中,我们通常使用一个表格来存储中间计算结果,以避免重复计算。动态规划通常采用自底向上的方法,从最简单的子问题开始,逐步解决更复杂的问题。在本文中,我们将演示如何使用动态规划算法解决上述三个问题。

一、最长公共子序列

问题描述:给定两个字符串s1和s2,找出它们的最长公共子序列(LCS)。LCS是指在两个给定序列中同时出现的最长子序列。一个序列是另一个序列的子序列,当且仅当它们在原序列中以相同的顺序出现,但不一定连续。

举个例子,如果s1 = "abcde",s2 = "ace",那么它们的LCS是"ace",长度为3。

解决方案:我们可以使用动态规划算法来解决这个问题。我们可以定义一个二维数组dp[i][j]来表示s1的前i个字符和s2的前j个字符的LCS长度。如果s1[i] == s2[j],那么dp[i][j] = dp[i-1][j-1] + 1;否则,dp[i][j] = max(dp[i-1][j], dp[i][j-1])。最终,LCS的长度就是dp[m][n],其中m和n分别是s1和s2的长度。

Java代码:


public int longestCommonSubsequence(String text1, String text2) {
    int m = text1.length();
    int n = text2.length();
    int[][] dp = new int[m+1][n+1];
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (text1.charAt(i-1) == text2.charAt(j-1)) {
                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[m][n];
}

二、不相交的线

问题描述:在一个二维平面上,有两条线段A和B,它们不能相交。我们需要找到在A和B中分别选取几个点,使得这些点的连线不相交,并且点的数量最多。

举个例子,如果A = [1, 4, 2],B = [1, 2, 4],那么最多可以选取两个点,它们的索引分别是0和2。

解决方案:我们可以使用动态规划算法来解决这个问题。我们可以定义一个二维数组dp[i][j]来表示A的前i个元素和B的前j个元素中,选取的点的数量最多。如果A[i-1] == B[j-1],那么dp[i][j] = dp[i-1][j-1] + 1;否则,dp[i][j] = max(dp[i-1][j], dp[i][j-1])。最终,答案就是dp[m][n],其中m和n分别是A和B的长度。

Java代码:

public int maxUncrossedLines(int[] A, int[] B) {
    int m = A.length;
    int n = B.length;
    int[][] dp = new int[m+1][n+1];
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (A[i-1] == B[j-1]) {
                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[m][n];
}

三、最大子序和

问题描述:给定一个整数数组nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

举个例子,如果nums = [-2,1,-3,4,-1,2,1,-5,4],那么最大子序和是6,由子数组[4,-1,2,1]组成。

解决方案:我们可以使用动态规划算法来解决这个问题。我们可以定义一个一维数组dp[i]来表示以nums[i]结尾的连续子数组的最大和。如果dp[i-1] > 0,那么dp[i] = dp[i-1] + nums[i];否则,dp[i] = nums[i]。最终,最大子序和就是dp数组中的最大值。

Java代码:

public int maxSubArray(int[] nums) {
    int n = nums.length;
    int[] dp = new int[n];
    dp[0] = nums[0];
    int maxSum = nums[0];
    for (int i = 1; i < n; i++) {
        dp[i] = nums[i];
        if (dp[i-1] > 0) {
            dp[i] += dp[i-1];
        }
        maxSum = Math.max(maxSum, dp[i]);
    }
    return maxSum;
}

总结

本文介绍了如何使用动态规划算法高效地解决三个经典问题:最长公共子序列、不相交的线和最大子序和。动态规划算法是一种非常有用的算法,可以用来解决各种计算问题,包括图形识别、自然语言处理、机器学习等领域。在实际应用中,我们需要根据具体问题的特点选择合适的动态规划方法,并结合具体的编程语言来实现算法。