返回
相交的智慧:1035 不相交的线
后端
2024-02-02 17:15:02
导言
算法世界的迷宫中,动态规划(DP)宛如一道耀眼的明灯,引领我们破解复杂问题。在今天的探险中,我们聚焦于一道经典的 DP 问题:不相交的线(1035)。
问题
我们有两条水平线,分别标有数字序列 nums1
和 nums2
。我们的任务是将这些数字写入两条线,使其满足以下条件:
- 同一条线上的数字必须按照给定的顺序书写。
- 两条线上的数字不能相交(即不能在同一点重叠)。
解题思路
运用 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])
动态规划过程
- 初始化:
dp[0][0] = 0
。 - 按序考虑
nums1
和nums2
中的数字:- 若两数字不相交,则更新
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 的强大之处。通过巧妙分解问题和优化实现,我们找到了相交的智慧,获取了问题最优解。