代码随想录Day 44|leetcode题目:1143.最长公共子序列、1035.不相交的线、53. 最大子序和、392.判断子序列

news2024/11/15 3:40:54

提示:DDU,供自己复习使用。欢迎大家前来讨论~

文章目录

  • 题目
    • 题目一:1143.最长公共子序列
      • 解题思路:
    • 题目二: 1035.不相交的线
      • 解题思路:
    • 题目三:53. 最大子序和
      • 解题思路
    • 题目四:392.判断子序列
    • 解题思路
      • 1. **确定 dp 数组的含义**
      • 2. **确定递推公式**
      • 3. **初始化 dp 数组**
      • 4. **确定遍历顺序**
      • 5. **举例推导 dp 数组**
      • 6. **代码实现**
    • 总结

动态规划Part11

题目

题目一:1143.最长公共子序列

1143. 最长公共子序列

解题思路:

动规五部曲分析如下:

  1. 确定dp数组(dp table)以及下标的含义

在动态规划中定义dp[i][j]时,选择将字符串的长度定义为[0, i - 1]而非[0, i]的原因主要是为了简化代码实现,特别是在初始化dp数组的第一行和第一列时。这种定义方式可以使得初始化逻辑更加直观和简便。尽管也可以选择[0, i]作为定义方式,但前者在实际操作中更为常见,因为它减少了边界条件处理的复杂性。

  1. 确定递推公式

主要就是两大情况:

  • text1[i - 1] 与 text2[j - 1]相同
  • text1[i - 1] 与 text2[j - 1]不相同

如果text1[i - 1] 与 text2[j - 1]相同,那么找到了一个公共元素,所以dp[i][j] = dp[i - 1][j - 1] + 1;

如果text1[i - 1] 与 text2[j - 1]不相同,那就看看text1[0, i - 2]与text2[0, j - 1]的最长公共子序列 和 text1[0, i - 1]与text2[0, j - 2]的最长公共子序列,取最大的。

即:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);

代码如下:

if (text1[i - 1] == text2[j - 1]) {
    dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
  1. dp数组如何初始化

在最长公共子序列问题中,dp[i][0]dp[0][j] 都初始化为0,因为非空字符串与空字符串的最长公共子序列长度为0。其他dp值根据递推关系计算得到。

代码:

vector<vector<int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));
  1. 确定遍历顺序

从递推公式,可以看出,有三个方向可以推出dp[i][j],如图:

1143.最长公共子序列

那么为了在递推的过程中,这三个方向都是经过计算的数值,所以要从前向后,从上到下来遍历这个矩阵。

  1. 举例推导dp数组

以输入:text1 = “abcde”, text2 = “ace” 为例,dp状态如图:

1143.最长公共子序列1

最后红框dp[text1.size()][text2.size()]为最终结果

以上分析完毕,C++代码如下:

class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        vector<vector<int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));
        for (int i = 1; i <= text1.size(); i++) {
            for (int j = 1; j <= text2.size(); j++) {
                if (text1[i - 1] == text2[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[text1.size()][text2.size()];
    }
};
  • 时间复杂度: O(n * m),其中 n 和 m 分别为 text1 和 text2 的长度
  • 空间复杂度: O(n * m)

题目二: 1035.不相交的线

1035. 不相交的线

解题思路:

绘制一些连接两个数字 A[i] 和 B[j] 的直线,只要 A[i] == B[j],且直线不能相交!

直线不能相交,这就是说明在字符串A中 找到一个与字符串B相同的子序列,且这个子序列不能改变相对顺序,只要相对顺序不改变,链接相同数字的直线就不会相交。

拿示例一A = [1,4,2], B = [1,2,4]为例,相交情况如图:

img

其实也就是说A和B的最长公共子序列是[1,4],长度为2。 这个公共子序列指的是相对顺序不变(即数字4在字符串A中数字1的后面,那么数字4也应该在字符串B数字1的后面)

这么分析完之后,大家可以发现:本题说是求绘制的最大连线数,其实就是求两个字符串的最长公共子序列的长度!

本题代码如下:

class Solution {
public:
    int maxUncrossedLines(vector<int>& A, vector<int>& B) {
        vector<vector<int>> dp(A.size() + 1, vector<int>(B.size() + 1, 0));
        for (int i = 1; i <= A.size(); i++) {
            for (int j = 1; j <= B.size(); j++) {
                if (A[i - 1] == B[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[A.size()][B.size()];
    }
};
  • 时间复杂度: O(n * m)
  • 空间复杂度: O(n * m)

题目三:53. 最大子序和

53. 最大子数组和

解题思路

这次我们用动态规划的思路再来分析一次。

动规五部曲如下:

  1. 确定dp数组(dp table)以及下标的含义

dp[i]:包括下标i(以nums[i]为结尾)的最大连续子序列和为dp[i]

  1. 确定递推公式

dp[i]只有两个方向可以推出来:

  • dp[i - 1] + nums[i],即:nums[i]加入当前连续子序列和
  • nums[i],即:从头开始计算当前连续子序列和

一定是取最大的,所以dp[i] = max(dp[i - 1] + nums[i], nums[i]);

  1. dp数组如何初始化

从递推公式可以看出来dp[i]是依赖于dp[i - 1]的状态,dp[0]就是递推公式的基础。

dp[0]应该是多少呢?

根据dp[i]的定义,很明显dp[0]应为nums[0]即dp[0] = nums[0]。

  1. 确定遍历顺序

递推公式中dp[i]依赖于dp[i - 1]的状态,需要从前向后遍历。

  1. 举例推导dp数组

以示例一为例,输入:nums = [-2,1,-3,4,-1,2,1,-5,4],对应的dp状态如下: 53.最大子序和(动态规划)

注意最后的结果可不是dp[nums.size() - 1]! ,而是dp[6]。

以上动规五部曲分析完毕,完整代码如下:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if (nums.size() == 0) return 0;
        vector<int> dp(nums.size());
        dp[0] = nums[0];
        int result = dp[0];
        for (int i = 1; i < nums.size(); i++) {
            dp[i] = max(dp[i - 1] + nums[i], nums[i]); // 状态转移公式
            if (dp[i] > result) result = dp[i]; // result 保存dp[i]的最大值
        }
        return result;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

题目四:392.判断子序列

392. 判断子序列

解题思路

这个问题是判断一个字符串 s 是否为另一个字符串 t 的子序列。以下是解决这个问题的动态规划方法的关键步骤:

1. 确定 dp 数组的含义

  • dp[i][j] 表示字符串 s 的前 i 个字符和字符串 t 的前 j 个字符的最长相同子序列的长度。

2. 确定递推公式

  • 如果 s[i-1] 等于 t[j-1],则 dp[i][j] = dp[i-1][j-1] + 1
  • 如果 s[i-1] 不等于 t[j-1],则 dp[i][j] = dp[i][j-1],相当于在 t 中跳过字符 t[j-1]

3. 初始化 dp 数组

  • dp[0][j] 初始化为 0,表示空字符串 s 与任意前缀的 t 的子序列长度为 0。
  • dp[i][0] 同理,初始化为 0。

4. 确定遍历顺序

  • 从左到右、从上到下遍历,因为 dp[i][j] 的值依赖于其左边和上边的值。

5. 举例推导 dp 数组

  • 通过具体例子(如 s = "abc"t = "ahbgdc")来手动计算 dp 数组,验证递推公式的正确性。

6. 代码实现

class Solution {
public:
    bool isSubsequence(string s, string t) {
        int m = s.size(), n = t.size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (s[i - 1] == t[j - 1])
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                else
                    dp[i][j] = dp[i][j - 1];
            }
        }
        return dp[m][n] == m;
    }
};
  • 时间复杂度:O(n × m),其中 nm 分别是字符串 st 的长度。
  • 空间复杂度:O(n × m),用于存储 dp 数组。

这种方法确保了通过动态规划有效计算两个字符串的最长相同子序列的长度,从而判断 s 是否为 t 的子序列。

总结

  1. 只考虑了编辑距离中的删除操作,而没有涉及插入和替换,这降低了问题的复杂性。
  2. 动态规划应用:通过动态规划方法,使用二维数组 dp 来记录和计算子问题的解,其中 dp[i][j] 表示考虑字符串 s 的前 i 个字符和字符串 t 的前 j 个字符时的最长相同子序列的长度。
  3. 状态转移
    • 匹配情况:如果 s[i - 1] 等于 t[j - 1],则在之前的基础上增加1,即 dp[i][j] = dp[i - 1][j - 1] + 1
    • 不匹配情况:如果 s[i - 1] 不等于 t[j - 1],则取忽略 s 的当前字符或忽略 t 的当前字符所得到的最大长度,即 dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2139108.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【白话树】之 二叉树

快速导航 一、二叉树的基本概念1、 二叉树定义2、常见术语3、基本操作1&#xff09;创建&#xff1a;2&#xff09;插入与删除&#xff1a; 4、常见类型1&#xff09;满二叉树&#xff08;完美二叉树&#xff09;2&#xff09;完全二叉树3&#xff09;完满二叉树4&#xff09;平…

Mysql InnoDB 存储引擎简介

InnoDB 存储引擎是 Mysql 的默认存储引擎&#xff0c;它是由 Innobase Oy 公司开发的 Mysql 为什么默认使用 InnoDB 存储引擎 InnoDB 是一款兼顾高可靠性和高性能的通用存储引擎 在 Mysql 5.5 版本之前&#xff0c;默认是使用 MyISAM 存储引擎&#xff0c;在 5.5 及其之后版…

WEB打点

目录 web打点概述打点流程打点中的问题getshell手法汇总web打点批量检测端口扫描POC扫描指纹识别漏洞扫描 手工检测开源框架漏洞通用框架漏洞基础web漏洞商用系统漏洞 WAF绕过waf分类常见waf拦截界面WAF绕过思路侧面绕&#xff1a;适合云WAF直面WAF web打点概述 打点流程 资产…

远程Linux网络连接( Linux 网络操作系统 04)

接下来我们准备开始进入Linux操作系统的第二个模块的学习&#xff0c;不过在学习之前我们需要对如下进行简单的配置&#xff0c;通过外接辅助软件MobaXterm来进行虚拟操作系统的访问。接下来的课程我们会一直在MobaXterm中进行命令和相关知识的学习。 一、准备阶段 1.1 软件 …

安装配置filebrowser

安装配置filebrowser ​ 这章就简单搞个工具用一下&#xff0c;这个工具就是一个像安卓软件一样的文件浏览器&#xff0c;可以设置用户权限啥的&#xff0c;挺好用的下面直接粘的安装步骤&#xff0c;注意一下配置别错了就行&#xff0c;json文件和命令配置要一样。访问效果放…

逻辑回归原理

本文主要介绍了逻辑回归的原理和应用&#xff0c;包括从线性回归到逻辑回归的转换、二元逻辑回归的模型和损失函数、优化方法以及正则化等内容。以下是内容的详细叙述&#xff1a; 1. 从线性回归到逻辑回归 线性回归模型&#xff1a;线性回归是找出输出特征向量Y与输入样本矩阵…

无线通信感知/雷达系统算法专业技术栈

无论是在工业界还是在学业界&#xff0c;无线通信感知一体化都是一个热门的方向&#xff0c;作为一个24届毕业生&#xff0c;刚好处于行业当中&#xff0c;就总结一下自己浅薄认知下&#xff0c;自己觉得已经掌握或者应该掌握的技术栈和专业能力&#xff0c;与大家共勉。 Rada…

CS61C 2020计算机组成原理Lab01-数字表示,溢出

1. Exercise 1 :See what you can C # 用gcc 来编译可执行文件如program.c gcc program.c # 就可以得到一个executable file named a.out. ./a.out# 如果想给这个可执行文件命名&#xff0c;则使用 -o gcc -o program program.c ./program# 使用-g 能得到一个 可执行程序的deb…

微服务保护之熔断降级

在微服务架构中&#xff0c;服务之间的调用是通过网络进行的&#xff0c;网络的不确定性和依赖服务的不可控性&#xff0c;可能导致某个服务出现异常或性能问题&#xff0c;进而引发整个系统的故障&#xff0c;这被称为 微服务雪崩。为了防止这种情况发生&#xff0c;常用的一些…

K8s 之控制器的定义及详细调用案例

什么是控制器 官方文档&#xff1a; https://v1-30.docs.kubernetes.io/zh-cn/docs/concepts/workloads/controllers/ 控制器也是管理pod的一种手段 自主式pod&#xff1a;pod退出或意外关闭后不会被重新创建控制器管理的 Pod&#xff1a;在控制器的生命周期里&#xff0c;始…

《深度学习》PyTorch 手写数字识别 案例解析及实现 <下>

目录 一、回顾神经网络框架 1、单层神经网络 2、多层神经网络 二、手写数字识别 1、续接上节课代码&#xff0c;如下所示 2、建立神经网络模型 输出结果&#xff1a; 3、设置训练集 4、设置测试集 5、创建损失函数、优化器 参数解析&#xff1a; 1&#xff09;para…

Cesium 计算3d凸包(ConvexHull)

Cesium 计算3d凸包(ConvexHull) Cesium 计算3d凸包(ConvexHull)

Unity实战案例全解析:PVZ 植物放置分析

前篇&#xff1a;Unity实战案例全解析&#xff1a;PVZ 植物卡片状态分析-CSDN博客 植物应该如何从卡牌状态转为实物&#xff1f; 其实就只需要考虑两个步骤加一个后续处理&#xff1a; 1.点击卡牌后就实例化 需要一个植物状态枚举&#xff0c;因为卡牌分为拿在手上和种植下…

Android 10.0 mtk平板camera2横屏预览旋转90度横屏保存圆形预览缩略图旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,点击录像和照片下保存的圆形预览缩略图 依然是竖屏的,所以说同样需要…

需求导向的正则表达式

目录 re.sub 需求&#xff1a;把 1. 2.这些序号转成&#xff08;1&#xff09; &#xff08;2&#xff09; 需求&#xff1a;反过来&#xff0c;把(1)->1. ,&#xff08;2&#xff09;》2. 。 需求&#xff1a;把出现的 1 2 3都转成下标 进阶1&#xff01;只想让化学符…

Redis入门2

在java中操作Redis Redis的Java客户端 Redis 的 Java 客户端很多&#xff0c;常用的几种: Jedis Lettuce Spring Data Redis Spring Data Redis 是 Spring 的一部分&#xff0c;对 Redis 底层开发包进行了高度封装。 在 Spring 项目中&#xff0c;可以使用Spring Data R…

把项目部署到Linux系统上(如何在阿里云服务器上安装和配置SpringBoot+vue全栈开发环境)

项目部署上线 环境准备下载安装Linux系统和ssh连接工具背景知识安装虚拟机安装Linux系统选择installCentOS7按命令IP addr查看服务器IP地址&#xff0c;ens33网卡中会出现IP地址配置好后就可以查看了一个可远程连接Linux服务器的工具1.&#xff08;基于finalshell工具&#xff…

小明震惊OpenAI 的新模型 01

在硅谷的中心&#xff0c;繁忙的咖啡馆和创业中心周围&#xff0c;年轻的软件工程师小明坐在他的办公桌前&#xff0c;面露困惑。科技界一直在盛传一项新的AI突破&#xff0c;但他持怀疑态度&#xff0c;不敢抱太大希望。他认为AI泡沫即将破灭&#xff0c;炒作列车即将出轨&…

网络原理 IP协议与以太网协议

博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:MySQL数据库 JavaEE专栏:JavaEE 关注博主带你了解更多数据结构知识 目录 1.网络层 IP协议 1.IP协议格式 2.地址管理 2.1 IP地址 2.2 解决IP地址不够用的问题 2.3NAT网络地址转换 2.4网段划分 3.路由选择…

北极星计划的回响:从Leap Motion到Midjourney的AI 3D硬件梦想

在科技的浩瀚星空中,总有一些梦想如同北极星般璀璨,指引着探索者前行。六年前,Leap Motion的CEO David以一篇充满激情的博客文章,向我们揭示了“北极星计划”——一个旨在打破数字与物理界限,创造流畅统一体验的增强现实平台。今天,随着Midjourney在AI文生图领域的全球爆…