LeetCode1035. 不相交的线(二维动态规划)

题目

在两条独立的水平线上按给定的顺序写下 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[i1]==nums2[j1]时,   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[i1][j1]+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[i1]!=nums2[j1]时,   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[i1][j],dp[i][j1])

代码:

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];
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值