[Mdp] lc1035. 不相交的线(LCS+LIS+重点知识理解)

15 篇文章 0 订阅
8 篇文章 0 订阅

1. 题目来源

链接:1035. 不相交的线

相关:


力赞题解,知识总结,对比 LCS 与 LIS 特性,深挖 LCS 状态分类,三叶姐yyds:

2. 题目解析

很有意思的一道题,不亏是小马AI,题单里的,哈哈。

一开始以为是做过的一道 思维+LIS,[线性dp] aw1012. 友好城市(最长上升子序列模型+思维)。看了看发现不是,然后就直接 dp 吧。然后发现和 lcs 思考过程一模一样…

做完之后看了三叶姐的题解,深受启发。 【宫水三叶の相信科学系列】求「最值问题」只需要确保「不漏」即可


  • 时间复杂度 O ( n m ) O(nm) O(nm)
  • 空间复杂度 O ( n m ) O(nm) O(nm)

代码:

写法一:四种情况的分类划分,状态之间有重叠,但不影响最值。经典的 LCS 状态划分。

在这里插入图片描述

图片取自 传送门:【宫水三叶の相信科学系列】求「最值问题」只需要确保「不漏」即可。 强烈建议看看分析。再去看看 [线性dp] aw897. 最长公共子序列(重要模板题+最长公共子序列模型)

class Solution {
public:
    int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
        int n = nums1.size(), m = nums2.size();
        vector<vector<int>> f(n + 1, vector<int>(m + 1));

        for (int i = 1; i <= n; i ++ ) 
            for (int j = 1; j <= m; j ++ ) {
                f[i][j] = max(f[i - 1][j], f[i][j - 1]);
                if (nums1[i - 1] == nums2[j - 1]) f[i][j] = max(f[i][j], f[i - 1][j - 1] + 1);
            }

        return f[n][m];
    }
};

写法二:LCS 的优化,仅判断 a[i]==b[j],只分两种情况,状态转移加 if-else,代码结构与朴素版的一样。更加简洁。

其实经过仔细比对,会发现,当 a[i]==b[j] 时,状态一定由 f[i-1][j-1]+1 进行转移,就不需要通过 f[i][j] = max(f[i - 1][j], f[i][j - 1]); 这个转移了。但朴素的写法,会将这个放到前面,使其先判断不等,再判断相等。

重点理解:

  • 其中,a[i]==b[j] 只需要 f[i][j]=f[i-1][j-1]+1 参与状态转移,而不需要其它的来进行大小比较。例如和四种状态划分一样,当 a[i]==b[j] 时,f[i][j]=max(f[i-1][j],f[i][j-1],f[i-1][j-1]+1) 这三个值来比大小。以其中一个为例,f[i][j-1] 相较于 f[i-1][j-1]+1 是多了一个 a[i] 元素的,那么如果这个 a[i] 元素匹配了 b 串中的某一个,也不过是 +1 的贡献量,顶多与 f[i-1][j-1]+1 持平。如果不匹配,甚至还不如 f[i-1][j-1]+1,那么取 max 自然取不到它。 所以直接通过 f[i][j]=f[i-1][j-1]+1 进行状态转移。
  • 所以,在 a[i]==b[j] 状态转移时进行一个小优化。两种方法的代码实现将完全一致。
class Solution {
public:
    int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
        int n = nums1.size(), m = nums2.size();
        vector<vector<int>> f(n + 1, vector<int>(m + 1));

        for (int i = 1; i <= n; i ++ ) 
            for (int j = 1; j <= m; j ++ ) {
                if (nums1[i - 1] == nums2[j - 1]) f[i][j] = f[i - 1][j - 1] + 1;    // 直接转移
                else f[i][j] = max(f[i - 1][j], f[i][j - 1]);
            }

        return f[n][m];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值