动态规划—1035. 不相交的线
- 题目描述
- 前言介绍
- 基本思路
- 1. 问题定义
- 2. 理解问题和递推关系
- 动态规划递推公式:
- 边界条件:
- 3. 解决方法
- 动态规划方法
- 伪代码:
- 4. 进一步优化
- 5. 小总结
- Python代码
- Python代码解释总结:
- C++代码
- C++代码解释总结:
- 最终总结
题目描述
前言介绍
Uncrossed Lines(不相交的线问题) 是一个典型的动态规划问题,它的解法与 最长公共子序列(LCS, Longest Common Subsequence) 非常相似。我们可以把该问题视作两个数组之间的最大匹配问题,其中相同的数字可以连成一条线,而我们要求这些线相互不交叉。通过动态规划来计算两个数组中的最长公共子序列的长度,我们可以有效地解决这个问题。
基本思路
1. 问题定义
给定两个整数数组 nums1
和 nums2
,找出它们之间不相交线段的最大数量。一个线段将 nums1[i]
连接到 nums2[j]
,当 nums1[i] == nums2[j]
时,且这些线段之间不能交叉。
2. 理解问题和递推关系
该问题可以转化为 最长公共子序列(LCS) 问题。在 nums1
和 nums2
中,相同的元素可以看作是一个匹配,并且这些匹配不应相互交叉。最大不相交线段数量就是两个数组中能找到的最长公共子序列的长度。
动态规划递推公式:
定义一个二维数组 dp[i][j]
,表示 nums1
的前 i
个元素与 nums2
的前 j
个元素之间能连接的最多不相交线段数量。
-
如果
nums1[i-1] == nums2[j-1]
,则有:
d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 dp[i][j] = dp[i-1][j-1] + 1 dp[i][j]=dp[i−1][j−1]+1
这表示我们可以在nums1[i-1]
和nums2[j-1]
之间画一条不相交的线段。 -
如果
nums1[i-1] != nums2[j-1]
,则:
d p [ i ] [ j ] = max ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) dp[i][j] = \max(dp[i-1][j], dp[i][j-1]) dp[i][j]=max(dp[i−1][j],dp[i][j−1])
这表示我们可以选择不连接nums1[i-1]
或nums2[j-1]
,但保持之前的最大不相交线段数。
边界条件:
dp[0][*] = 0
和dp[*][0] = 0
,因为当其中一个数组为空时,不可能有任何不相交的线段。
3. 解决方法
动态规划方法
- 定义
dp[i][j]
表示nums1
的前i
个元素与nums2
的前j
个元素之间的最大不相交线段数。 - 使用递推公式进行状态转移。
- 最终,
dp[m][n]
(m
和n
分别是nums1
和nums2
的长度)就是我们需要的最大不相交线段数。
伪代码:
initialize dp array with size (m+1) x (n+1) with 0s
for i from 1 to m:for j from 1 to n:if nums1[i-1] == nums2[j-1]:dp[i][j] = dp[i-1][j-1] + 1else:dp[i][j] = max(dp[i-1][j], dp[i][j-1])
return dp[m][n]
4. 进一步优化
- 该算法的时间复杂度为
O(m * n)
,可以通过动态规划中的滚动数组优化空间复杂度到O(n)
。
5. 小总结
- 递推思路:通过逐步递推,比较两个数组的元素是否相等,动态规划可以有效解决这个问题。
- 时间复杂度:时间复杂度为
O(m * n)
,可以处理中等规模的输入。
以上就是不相交的线问题的基本思路。
Python代码
class Solution:def maxUncrossedLines(self, nums1: list[int], nums2: list[int]) -> int:m, n = len(nums1), len(nums2)# 初始化dp数组,大小为(m+1) x (n+1)dp = [[0] * (n + 1) for _ in range(m + 1)]# 填充dp数组for i in range(1, m + 1):for j in range(1, n + 1):if nums1[i - 1] == nums2[j - 1]:dp[i][j] = dp[i - 1][j - 1] + 1else:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])# 返回不相交线段的最大数量return dp[m][n]
Python代码解释总结:
- 初始化:创建一个二维数组
dp
,大小为(m+1) x (n+1)
,用于记录每个位置的最大不相交线段数。 - 动态填充:根据
nums1[i-1]
和nums2[j-1]
的关系,使用递推公式来更新dp
数组。 - 返回结果:
dp[m][n]
存储了nums1
和nums2
的最大不相交线段数。
C++代码
class Solution {
public:int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {int m = nums1.size(), n = nums2.size();// 初始化dp数组,大小为(m+1) x (n+1)vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));// 填充dp数组for (int i = 1; i <= m; ++i) {for (int j = 1; j <= n; ++j) {if (nums1[i - 1] == nums2[j - 1]) {dp[i][j] = dp[i - 1][j - 1] + 1;} else {dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);}}}// 返回不相交线段的最大数量return dp[m][n];}
};
C++代码解释总结:
- 初始化:创建一个二维数组
dp
,用于存储每个位置的最大不相交线段数。 - 动态填充:遍历
nums1
和nums2
,并根据元素的匹配情况更新dp
数组。 - 返回结果:最终
dp[m][n]
即为最大不相交线段数。
最终总结
- 问题核心:不相交的线问题可以看作两个数组之间的最长公共子序列问题,通过动态规划有效求解。
- 时间复杂度:时间复杂度为
O(m * n)
,其中m
和n
分别是nums1
和nums2
的长度。 - 空间优化:可以通过滚动数组优化空间复杂度,从
O(m * n)
降低到O(n)
。 - 应用场景:该问题是动态规划与序列匹配的经典问题之一,掌握这一类问题的解法对于解决类似的匹配问题有重要帮助。