题目
在两条独立的水平线上按给定的顺序写下 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 的直线相交。
解答
问题花里胡哨说了一堆,究其本质,其实是求解数组 nums1和 nums2的最长公共子序列的长度。
给定两个数组 nums1和 nums2,当
n
u
m
s
1
[
i
]
=
=
n
u
m
s
2
[
j
]
\ nums1\left [ i\right ] == nums2\left [ j\right ]
nums1[i]==nums2[j]时,可以用一条直线连接 nums1[i]和nums2[j]。假设一共绘制了 k 条互不相交的直线,其中第 x 条直线连接
n
u
m
s
1
[
i
x
]
\ nums1\left [ i_x \right ]
nums1[ix]和
n
u
m
s
2
[
j
x
]
\ nums2\left [ j_x \right ]
nums2[jx],则对于任意
1
<
x
<
k
\ 1< x < k
1<x<k都有
n
u
m
s
1
[
i
x
]
=
=
n
u
m
s
2
[
j
x
]
\ nums1\left [ i_x \right ] == nums2\left [ j_x \right ]
nums1[ix]==nums2[jx],其中
i
1
<
i
2
<
i
k
\ i_{1} < i_{2} <i_{k}
i1<i2<ik,
j
1
<
j
2
<
j
k
\ j_{1} < j_{2} < j_{k}
j1<j2<jk。上述 k 条互不相交的直线分别连接了数组 nums1 和 nums 2的 k 对相等的元素,而且这 k 对相等的元素在两个数组中的相对顺序是一致的,因此,这 k 对相等的元素组成的序列即为数组 nums1 和 nums2的公共子序列。
求解公共子序列是典型的二维动态规划问题。
假设数组 nums1和 nums2 的长度分别为 m 和 n,创建 m+1 行 n+1 列的二维数组 dp,其中
d
p
[
i
]
[
j
]
\ dp\left [ i \right ]\left [ j \right ]
dp[i][j]表示
n
u
m
s
1
[
0
:
1
]
\ nums1\left [ 0:1 \right ]
nums1[0:1]和
n
u
m
s
2
[
0
:
j
]
\ nums2\left [ 0:j \right ]
nums2[0:j]的最长公共子序列的长度。
n
u
m
s
1
[
0
:
1
]
\ nums1\left [ 0:1 \right ]
nums1[0:1]表示数组 nums1 的长度为 i 的前缀;
n
u
m
s
2
[
0
:
j
]
\ nums2\left [ 0:j \right ]
nums2[0:j]表示数组 nums2 的长度为 j 的前缀。
- 先考虑边界情况
- 当 i = 0 \ i=0 i=0 时, n u m s 1 [ 0 : i ] \ nums1\left [ 0:i \right ] nums1[0:i] 为空,空数组和任何数组的最长公共子序列的长度都是 0,因此对任意 0 < = j < = n \ 0 <= j <= n 0<=j<=n有 d p [ 0 ] [ j ] = = 0 \ dp\left [ 0 \right ]\left [ j \right ] == 0 dp[0][j]==0;
- 当 j = 0 \ j=0 j=0 时, n u m s 2 [ 0 : j ] \ nums2\left [ 0:j \right ] nums2[0:j] 为空,同理可得,对任意 0 < = i < = m \ 0 <= i <= m 0<=i<=m有 d p [ i ] [ 0 ] = = 0 \ dp\left [ i \right ]\left [ 0 \right ] == 0 dp[i][0]==0;
- 当
i
>
0
,
j
>
0
\ i>0,j>0
i>0,j>0时,考虑
d
p
[
i
]
[
j
]
\ dp\left [ i \right ]\left [ j \right ]
dp[i][j]的计算:
- n u m s 1 [ i − 1 ] = = n u m s 2 [ j − 1 ] \ nums1\left [ i-1 \right ] == nums2\left [ j-1 \right ] nums1[i−1]==nums2[j−1]时, d p [ i ] [ j ] = = d p [ i − 1 ] [ j − 1 ] + 1 \ dp\left [ i \right ]\left [ j \right ] == dp\left [ i-1 \right ]\left [ j-1 \right ]+1 dp[i][j]==dp[i−1][j−1]+1
- n u m s 1 [ i − 1 ] ! = n u m s 2 [ j − 1 ] \ nums1\left [ i-1 \right ] != nums2\left [ j-1 \right ] nums1[i−1]!=nums2[j−1]时, d p [ i ] [ j ] = = m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) \ dp\left [ i \right ]\left [ j \right ] == max(dp\left [ i-1 \right ]\left [ j \right ],dp\left [ i \right ]\left [ j-1 \right ] ) dp[i][j]==max(dp[i−1][j],dp[i][j−1])
代码:
class Solution {
public:
int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size(), n = nums2.size();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
for (int i = 1; i <= m; i++) {
int num1 = nums1[i - 1];
for (int j = 1; j <= n; j++) {
int num2 = nums2[j - 1];
if (num1 == num2) {
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];
}
};