算法沉淀——动态规划之两个数组的 dp(上)(leetcode真题剖析)

在这里插入图片描述

算法沉淀——动态规划之两个数组的 dp

  • 01.最长公共子序列
  • 02.不相交的线
  • 03.不同的子序列
  • 04.通配符匹配

01.最长公共子序列

题目链接:https://leetcode.cn/problems/longest-common-subsequence/

给定两个字符串 text1text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

  • 例如,"ace""abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。

两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

示例 1:

输入:text1 = "abcde", text2 = "ace" 
输出:3  
解释:最长公共子序列是 "ace" ,它的长度为 3 。

示例 2:

输入:text1 = "abc", text2 = "abc"
输出:3
解释:最长公共子序列是 "abc" ,它的长度为 3 。

示例 3:

输入:text1 = "abc", text2 = "def"
输出:0
解释:两个字符串没有公共子序列,返回 0 。 

提示:

  • 1 <= text1.length, text2.length <= 1000
  • text1text2 仅由小写英文字符组成。

思路

状态转移方程:

  1. 如果当前字符相同(text1[i] == text2[j]),说明我们找到了一个新的公共字符,因此最长公共子序列的长度在之前的基础上加 1:
    • dp[i][j] = dp[i - 1][j - 1] + 1
  2. 如果当前字符不同(text1[i] != text2[j]),则我们需要考虑去掉 text1[i] 或者去掉 text2[j] 之后的最长公共子序列。这可以通过比较 text1 的前 i-1 个字符和 text2 的前 j 个字符的最长公共子序列长度,以及 text1 的前 i 个字符和 text2 的前 j-1 个字符的最长公共子序列长度,取最大值:
    • dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

初始化:为了方便处理边界情况,我们在文本 text1text2 前各添加一个空字符,即 text1[0]text2[0] 表示空串。这样,dp 表的大小为 (m+1) x (n+1),其中 mn 分别是两个文本的长度。初始化时,将第一行和第一列的值都设置为 0。

填表顺序:最终的结果存储在 dp[m][n] 中,其中 mn 是两个文本的长度。这个值表示 text1text2 的最长公共子序列的长度。

代码

class Solution {
public:int longestCommonSubsequence(string text1, string text2) {int m=text1.size(),n=text2.size();text1=" "+text1,text2=" "+text2;vector<vector<int>> dp(m+1,vector<int>(n+1));for(int i=1;i<=m;i++)for(int j=1;j<=n;j++)if(text1[i]==text2[j]) 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];}
};

02.不相交的线

题目链接:https://leetcode.cn/problems/uncrossed-lines/

在两条独立的水平线上按给定的顺序写下 nums1nums2 中的整数。

现在,可以绘制一些连接两个数字 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

思路

如果我们希望确保两条直线不相交,我们可以将问题转化为在两个整数数组中寻找最长的公共子序列。这是因为,如果两条直线不相交,它们在同一列上对应的两个元素在两个数组中的顺序关系应该保持一致。

这个问题可以用动态规划来解决,具体步骤如下:

  1. 状态表达
    • 我们选取两个数组分别表示两条直线,数组长度分别为 mn
    • 定义状态表 dp,其中 dp[i][j] 表示数组1的前 i 个元素和数组2的前 j 个元素中的最长公共子序列的长度。
  2. 状态转移方程
    • 如果 nums1[i] == nums2[j],说明找到了一个公共元素,状态转移方程为 dp[i][j] = dp[i-1][j-1] + 1
    • 如果 nums1[i] != nums2[j],则需要在两个数组的前面部分分别寻找最长公共子序列,状态转移方程为 dp[i][j] = max(dp[i-1][j], dp[i][j-1])
  3. 初始化
    • 为了方便处理边界情况,可以在两个数组的前面各添加一个虚拟元素,表示空串。
    • 初始化 dp 数组的第一行和第一列为0,因为空串与任何数组的最长公共子序列长度都为0。
  4. 填表顺序
    • 从上到下,从左到右填写 dp 数组。
  5. 返回值
    • 最终的结果存储在 dp[m][n] 中,表示两个数组的最长公共子序列的长度。

代码

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++)for(int j=1;j<=n;j++)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];}   
};

03.不同的子序列

题目链接:https://leetcode.cn/problems/distinct-subsequences/

你两个字符串 st ,统计并返回在 s子序列t 出现的个数,结果需要对 109 + 7 取模。

示例 1:

输入:s = "rabbbit", t = "rabbit"
输出:3
解释:
如下所示, 有 3 种可以从 s 中得到 "rabbit" 的方案。
rabbbit
rabbbit
rabbbit

示例 2:

输入:s = "babgbag", t = "bag"
输出:5
解释:
如下所示, 有 5 种可以从 s 中得到 "bag" 的方案。 
babgbag
babgbag
babgbag
babgbag
babgbag

提示:

  • 1 <= s.length, t.length <= 1000
  • st 由英文字母组成

思路

  1. 状态表达

    • 选取第一个字符串 [0, i] 区间以及第二个字符串 [0, j] 区间作为研究对象,结合题目要求来定义状态表达。
    • 在这道题中,状态表达为 dp[i][j],表示在字符串 s[0, j] 区间内的所有子序列中,有多少个 t 字符串 [0, i] 区间内的子串。
  2. 状态转移方程

    • 根据最后一个位置的元素,结合题目要求进行分类讨论:

      • t[i] == s[j]
        

        时:

        • 选择 s[j] 作为结尾,相当于在状态 dp[i-1][j-1] 中的所有符合要求的子序列的后面,再加上一个字符 s[j],此时 dp[i][j] = dp[i-1][j-1]
        • 不选择 s[j] 作为结尾,相当于选择了状态 dp[i][j-1] 中所有符合要求的子序列,继承了上个状态里面的求得的子序列,此时 dp[i][j] = dp[i][j-1]
      • t[i] != s[j]
        

        时:

        • 子序列只能从 dp[i][j-1] 中选择所有符合要求的子序列,继承上个状态里面求得的子序列,此时 dp[i][j] = dp[i][j-1]
    • 综上,状态转移方程为:

      • 所有情况下都可以继承上一次的结果:dp[i][j] = dp[i][j-1]
      • t[i] == s[j] 时,可以多选择一种情况:dp[i][j] += dp[i-1][j-1]
  3. 初始化

    • 引入空串后,方便初始化,注意下标的映射关系以及确保后续填表是正确的。
    • s 为空时,t 的子串中有一个空串和它一样,因此初始化第一行全部为 1
  4. 填表顺序

    • 从上往下填每一行,每一行从左往右。
  5. 返回值

    • 根据状态表达,返回 dp[m][n] 的值。

代码

class Solution {
public:int numDistinct(string s, string t) {int m=t.size(),n=s.size();vector<vector<double>> dp(m+1,vector<double>(n+1));for(int j=0;j<=n;j++) dp[0][j]=1;for(int i=1;i<=m;i++)for(int j=1;j<=n;j++){dp[i][j]+=dp[i][j-1];if(t[i-1]==s[j-1]) dp[i][j]+=dp[i-1][j-1];}return dp[m][n];}
};

04.通配符匹配

题目链接:https://leetcode.cn/problems/wildcard-matching/

给你一个输入字符串 (s) 和一个字符模式 (p) ,请你实现一个支持 '?''*' 匹配规则的通配符匹配:

  • '?' 可以匹配任何单个字符。
  • '*' 可以匹配任意字符序列(包括空字符序列)。

判定匹配成功的充要条件是:字符模式必须能够 完全匹配 输入字符串(而不是部分匹配)。

示例 1:

输入:s = "aa", p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。

示例 2:

输入:s = "aa", p = "*"
输出:true
解释:'*' 可以匹配任意字符串。

示例 3:

输入:s = "cb", p = "?a"
输出:false
解释:'?' 可以匹配 'c', 但第二个 'a' 无法匹配 'b'。

提示:

  • 0 <= s.length, p.length <= 2000
  • s 仅由小写英文字母组成
  • p 仅由小写英文字母、'?''*' 组成

思路

在处理两个字符串之间的动态规划问题时,通常按照以下步骤进行:

  1. 状态表达

    • 选取第一个字符串 [0, i] 区间以及第二个字符串 [0, j] 区间作为研究对象,结合题目的要求定义状态表达。
    • 在这道题中,我们定义状态表达为 dp[i][j],表示字符串 p[0, j] 区间内的子串能否匹配字符串 s[0, i] 区间内的子串。
  2. 状态转移方程

    • 根据最后一个位置的元素,结合题目要求,进行分类讨论:
      • s[i] == p[j]p[j] == '?' 时,两个字符串匹配上了当前的一个字符,只能从 dp[i-1][j-1] 中看当前字符前面的两个子串是否匹配,继承上个状态中的匹配结果,dp[i][j] = dp[i][j-1]
      • p[j] == '*' 时,匹配策略有两种选择:
        • 选择 '*' 匹配空字符串,相当于它匹配了一个寂寞,直接继承状态 dp[i][j-1]dp[i][j] = dp[i][j-1]
        • 选择 '*' 向前匹配 1 ~ n 个字符,直至匹配整个 s 串。相当于从 dp[k][j-1] (0 <= k <= i) 中所有匹配情况中,选择性继承可以成功的情况,dp[i][j] = dp[k][j-1] (0 <= k <= i)。
      • p[j] 不是特殊字符且不与 s[i] 相等时,无法匹配。综上,状态转移方程为:
        • s[i] == p[j]p[j] == '?' 时:dp[i][j] = dp[i-1][j-1]
        • p[j] == '*' 时,状态转移方程优化为:dp[i][j] = dp[i-1][j] || dp[i][j-1]
  3. 初始化

    • dp 数组的值表示是否匹配,初始化整个数组为 false
    • 由于需要用到前一行和前一列的状态,初始化第一行和第一列。
      • dp[0][0] 表示两个空串是否匹配,初始化为 true
      • 第一行表示 s 为空串,p 串与空串只有一种匹配可能,即 p 串表示为 "***",此时也相当于空串匹配上空串,将所有前导为 "*"p 子串与空串的 dp 值设为 true
      • 第一列表示 p 为空串,不可能匹配上 s 串,跟随数组初始化即可。
  4. 填表顺序

    • 从上往下填每一行,每一行从左往右。
  5. 返回值

    • 根据状态表达,返回 dp[m][n] 的值。

代码

class Solution {
public:bool isMatch(string s, string p) {int m=s.size(),n=p.size();s=" "+s,p=" "+p;vector<vector<bool>> dp(m+1,vector<bool>(n+1));dp[0][0]=true;for(int i=1;i<=n;i++)if(p[i]=='*') dp[0][i]=true;else break;for(int i=1;i<=m;i++)for(int j=1;j<=n;j++){if(p[j]=='*') dp[i][j]=dp[i][j-1]||dp[i-1][j];else dp[i][j]=(p[j]=='?'||s[i]==p[j])&&dp[i-1][j-1];}return dp[m][n];}
};

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

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

相关文章

0201sherlock(福尔摩斯)-通过名称寻找媒体账号(地址)-github-开源项目学习

文章目录 一 项目简介二 项目安装和演示1 安装2 演示 三 源码分析1 项目结构2 主程序源代码分析 四 添加自定义网址结语 一 项目简介 二 项目安装和演示 1 安装 # clone the repo $ git clone https://github.com/sherlock-project/sherlock.git# change the working direct…

opencv--使用直方图找谷底进行确定分割阈值

直方图原理就不说了&#xff0c;大家自行百度 直方图可以帮助分析图像中的灰度变化&#xff0c;进而帮助确定最优二值化的灰度阈值&#xff08;threshold level&#xff09;。如果物体与背景的灰度值对比明显&#xff0c;此时灰度直方图就会包含双峰&#xff08;bimodal histo…

Python web框架fastapi数据库操作ORM(一)

文章目录 Fastapi ORM操作1、创建模型2、创建数据库连接配置文件3、启动项目4、根据模型类创建数据库表1. 初始化配置&#xff0c;只需要使用一次2. 初始化数据库&#xff0c;一般情况下只用一次3. 更新模型并进行迁移4. 重新执行迁移&#xff0c;写入数据库5. 回到上一个版本6…

Oracle 11g升级19c 后部分查询功能很慢

*Oracle 11g升级19c 后部分查询功能很慢 今天生产突然有个查询非常慢&#xff0c;日志显示执行了50秒左右&#xff0c;但是从日志中拿出SQL在PLSQL执行&#xff0c;发现用时不到1秒&#xff0c;查看SQL,怀疑是下面几种原因导致 1、使用函数不当 UNIT.UNIT_CODE LIKE CONCAT(‘…

状态码转文字!!!(表格数字转文字)

1、应用场景&#xff1a;在我们的数据库表中经常会有status这个字段&#xff0c;这个字段经常表示此类商品的状态&#xff0c;例如&#xff1a;0->删除&#xff0c;1->上架&#xff0c;0->下架&#xff0c;等等。 2、我们返回给前端数据时&#xff0c;如果在页面显示0…

【Unity】在Unity中导出WebGL并读取Excel数据的实现方法

在游戏开发中&#xff0c;数据的处理和导出是至关重要的环节之一。Unity作为一款强大的游戏开发引擎&#xff0c;提供了丰富的工具和功能来处理和导出数据&#xff0c;包括将游戏导出为WebGL应用&#xff0c;并读取外部数据文件&#xff0c;比如Excel表格。本文将介绍如何在Uni…

gpt生成器,批量gpt文章生成器

GPT&#xff08;生成式预训练模型&#xff09;生成器软件在当今的数字化时代扮演着越来越重要的角色&#xff0c;它们通过人工智能技术&#xff0c;可以自动生成各种类型的文章内容&#xff0c;为用户提供了无限的创作可能性。本文将介绍6款不同的GPT生成器软件&#xff0c;并介…

STM32自学☞AD单通道

程序的最终运行成果: 当转动电位器时&#xff0c;数值和电压值发生变化 ad.c文件 #include "stm32f10x.h" #include "stm32f10x_adc.h" #include "ad.h" #include "stdint.h" void ad_Init(void) { /* 初始化步骤&#xff1a;…

java学习笔记-初级

一、变量 1.双标签 <!-- 外部js script 双标签 --><script srcmy.js></script> 在新文件my.js里面写&#xff1a; 2.字符串定义&#xff1a; //外单内双var str 我是一个"高富帅"的程序员;console.log(str);// 字符串转义字符 都是用 \ 开头 …

MySQL-MHA搭建、故障测试

一、架构说明 MHA&#xff08;Master High Availability&#xff09;是一个用于 MySQL 主从复制管理和自动故障转移的开源工具集。MHA 的主要目的是提供 MySQL 环境的高可用性和自动故障转移功能&#xff0c;确保在主库发生故障时能够快速切换到备库&#xff0c;降低业务中断时…

ElasticSearch之Completion Suggester

写在前面 通过completion suggester可以实现如下的效果&#xff1a; 其实就是做的like xxx%这种。通过FST这种数据结构来存储&#xff0c;实现快速的前缀匹配&#xff0c;并且可以将es所有的数据加载到内存中所以速度completion的查询速度非常快。 需要注意&#xff0c;如果…

HUAT——Fasc——算法组学习笔记

目录 系列文章目录 前言 一、配置相关环境 二、创建工作空间 1.创建工作空间并初始化 2.进入 src 创建 ros 包并添加依赖 三、HelloWorld(C版) 1.进入 ros 包的 src 目录编辑源文件 2.编辑 ros 包下的 Cmakelist.txt文件 3.进入工作空间目录并编译 四 运行程序 五 …

docker 基础(二)

常见命令 Docker最常见的命令就是操作镜像、容器的命令&#xff0c;详见官方文档&#xff1a;https://docs.docker.com/ 数据卷 命令说明文档地址docker volume create创建数据卷docker volume createdocker volume ls创建数据卷docker volume lsdocker volume rm查看所有数…

Swiper实现轮播效果

swiper官网&#xff1a;https://3.swiper.com.cn/ <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title&…

中间件-Nginx加固(控制超时时间限制客户端下载速度并发连接数)

中间件-Nginx加固&#xff08;控制超时时间&限制客户端下载速度&并发连接数&#xff09; 1.1 Nginx 控制超时时间配置1.2 Nginx 限制客户端下载速度&并发连接数 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 1.1 Nginx 控制超…

机器学习图像识别如何处理标签以外的图像?

机器学习图像识别技术是一种基于人工智能的图像处理方法&#xff0c;它通过训练大量的图像数据集来让计算机学习如何识别和分类图像。在图像识别任务中&#xff0c;我们通常需要对图像进行标注和分类&#xff0c;以便让计算机能够从中学习。但是&#xff0c;有时候我们可能会遇…

大数据旅游数据分析:基于Python旅游数据采集可视化分析推荐系统

文章目录 基于Python旅游数据采集可视化分析推荐系统一、项目概述二、项目说明三、开发环境四、功能实现五、系统页面实现用户登录注册系统首页数据操作管理价格与销量分析旅游城市和景点等级分析旅游数据评分情况分析旅游数据评论情况分析旅游景点推荐Django系统后台管理 六、…

【前端早早聊直播回顾】Harmony 时代的跨端方案

上周末&#xff0c;凡泰极客CTO - 徐鹏受邀出席「前端早早聊」直播活动&#xff0c;并以【跨端新挑战-鸿蒙时代的跨端】为主题进行演讲。 摘取部分分享实录&#xff1a; 终端系统的数量和种类不断增长&#xff0c;开发者面临着多平台开发的挑战。以往开发者一般只需要维护iOS、…

2024年3月阿里云服务器大规模价格下调后优惠折扣表

阿里云服务器ECS等核心产品价格全线下调&#xff0c;最高幅度达55%&#xff0c;2024年3月1日生效&#xff0c;针对ECS部分在售产品的官网折扣价、ECS计算型节省计划进行调整&#xff0c;生效后&#xff0c;基于官网折扣价的新购和续费&#xff0c;将按照新的价格进行计费。阿里…

程序媛的mac修炼手册-- Node.js入门篇

最近因为参与一个微信小程序的开发&#xff0c;开始摸索JavaScript。期间&#xff0c;需要基于Node.js安装微信开发工具的依赖项&#xff0c;所以又顺带学习了Node.js的包管理工具npm&#xff08;Node Package Manager&#xff09;。不过&#xff0c;之前看到国外的全栈大佬​​…