目录
题目
在两条独立的水平线上按给定的顺序写下 nums1
和 nums2
中的整数。现在,可以绘制一些连接两个数字 nums1[i]
和 nums2[j]
的直线,这些直线需要同时满足:
-
nums1[i] == nums2[j]
- 且绘制的直线不与任何其他连线(非水平线)相交。
请注意,连线即使在端点也不能相交:每个数字只能属于一条连线。以这种方法绘制线条,并返回可以绘制的最大连线数。
示例 1:
输入:nums1 = [1,4,2], nums2 = [1,2,4] 输出:2 解释:可以画出两条不交叉的线,如上图所示。 但无法画出第三条不相交的直线,因为从 nums1[1]=4 到 nums2[2]=4 的直线将与从 nums1[2]=2 到 nums2[1]=2 的直线相交。
示例 2:
输入:nums1 = [2,5,1,2,5], nums2 = [10,5,2,1,5,2] 输出:3
示例 3:
输入:nums1 = [1,3,7,1,7,5], nums2 = [1,9,2,5,1] 输出:2
提示:
1 <= nums1.length, nums2.length <= 500
1 <= nums1[i], nums2[j] <= 2000
思路
这个问题可以通过动态规划解决,具体方法是最长递增子序列(LIS)问题的变体。我们的目标是找出nums1
和nums2
中相同元素的最大匹配数,同时保证匹配的线段不会相交。这个问题可以转化为在nums2
中为nums1
中的每个元素找到一个位置,使得所有找到的位置在nums2
中是递增序列。
解题过程
-
初始化:创建一个列表
tails
,其长度与nums2
中不同元素的数量相同,初始值设为-1。这个列表将保存每个元素最后出现的位置。 -
填充
tails
:遍历nums2
,对于每个元素,如果它在tails
中尚未出现,则在tails
的末尾添加它的位置;如果已出现,则更新该元素在tails
中的值为当前位置。 -
计算最长不下降子序列:遍历
nums1
,对于每个元素,检查它在tails
中的位置。如果tails
中对应的位置不是-1,说明可以与nums1
中的当前元素匹配,更新答案长度。 -
返回答案:最终,答案即为
nums1
中可以找到的最长不下降子序列的长度。
复杂度
- 时间复杂度:
O(n×m)
,其中n
是nums1
的长度,m
是nums2
的长度。我们需要遍历nums1
和nums2
各一次。 - 空间复杂度:
O(m)
,最多需要存储nums2
中不同元素数量的索引,这个数量不会超过m
。
code
class Solution(object):
def maxUncrossedLines(self, nums1, nums2):
m, n = len(nums1), len(nums2)
# 初始化动态规划表
dp = [[0] * (n + 1) for _ in range(m + 1)]
# 填充动态规划表
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] + 1
else:
# 如果不相等,不能建立新的连线,取两个子问题的较大值
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
# 返回动态规划表的最后一个元素
return dp[m][n]
标签:连线,元素,相交,tails,dp,动态,规划,nums1,nums2 From: https://blog.csdn.net/Sxiaocai/article/details/141391688