返回

相交的智慧:1035 不相交的线

后端

导言

算法世界的迷宫中,动态规划(DP)宛如一道耀眼的明灯,引领我们破解复杂问题。在今天的探险中,我们聚焦于一道经典的 DP 问题:不相交的线(1035)。

问题

我们有两条水平线,分别标有数字序列 nums1nums2。我们的任务是将这些数字写入两条线,使其满足以下条件:

  • 同一条线上的数字必须按照给定的顺序书写。
  • 两条线上的数字不能相交(即不能在同一点重叠)。

解题思路

运用 DP 的精髓,我们将问题分解成子问题。令 dp[i][j] 表示考虑 nums1 中前 i 个数字和 nums2 中前 j 个数字时,满足不交叉条件的最大总和。

转移方程如下:

dp[i][j] = max(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1] + nums1[i - 1] + nums2[j - 1])

动态规划过程

  1. 初始化:dp[0][0] = 0
  2. 按序考虑 nums1nums2 中的数字:
    • 若两数字不相交,则更新 dp[i][j] 为三种可能性的最大值。
    • 若两数字相交,则令 dp[i][j] 为前一种情况下的最大值。

优化

为了优化空间复杂度,我们可以使用滚动数组,仅保留当前行和前一行的数据:

for (int j = 1; j <= n2; j++) {
    for (int i = 1; i <= n1; i++) {
        // 省略转移方程...
    }
    // 将前一行的数据复制到当前行
}

代码实现

class Solution {
    public int maxUncrossedLines(int[] nums1, int[] nums2) {
        int n1 = nums1.length, n2 = nums2.length;
        int[][] dp = new int[2][n2 + 1];
        
        for (int i = 1; i <= n1; i++) {
            for (int j = 1; j <= n2; j++) {
                if (nums1[i - 1] == nums2[j - 1]) {
                    dp[i % 2][j] = dp[(i - 1) % 2][j - 1] + 1;
                } else {
                    dp[i % 2][j] = Math.max(dp[(i - 1) % 2][j], dp[i % 2][j - 1]);
                }
            }
        }
        
        return dp[n1 % 2][n2];
    }
}

结论

1035 不相交的线问题体现了 DP 的强大之处。通过巧妙分解问题和优化实现,我们找到了相交的智慧,获取了问题最优解。