专题二十五_动态规划_两个数组的 dp (含字符串数组)_算法专题详细总结
目录
动态规划_两个数组的 dp (含字符串数组)
1. 最⻓公共⼦序列(medium)
解析:
1. 状态表⽰:
2. 状态转移⽅程:
3. 初始化:编辑
4. 填表顺序:编辑
5. 返回值:
代码编写:
总结:
2. 不相交的线(medium)
解析:
代码编写:
总结:
3. 不同的⼦序列(hard)
解析:
1. 状态表⽰:
2. 状态转移⽅程:编辑
3. 初始化:编辑
4. 填表顺序:
5. 返回值:编辑
总结:
4. 通配符匹配(hard)
解析:
1. 状态表⽰:
2. 状态转移⽅程:编辑
3. 初始化:编辑
4. 填表顺序:编辑
5. 返回值:
代码编写:
总结:
5. 正则表达式匹配(hard)
解释:
1. 状态表⽰:编辑
2. 状态转移⽅程:编辑
3. 初始化:编辑
4. 填表顺序:
5. 返回值:
代码编写:
总结:
6. 交错字符串(medium)
解析:
1. 状态表⽰:编辑
2. 状态转移⽅程:编辑
3. 初始化:编辑
4. 填表顺序:
5. 返回值:
代码编写:
总结:
7. 两个字符串的最⼩ ASCII 删除和(medium)
解析:
1. 状态表⽰:编辑
2. 状态转移⽅程:
3. 初始化:
4. 填表顺序:
5. 返回值:编辑
代码编写:
总结:
8. 最⻓重复⼦数组(medium)
解析:
1. 状态表⽰:编辑
2. 状态转移⽅程:编辑
3. 初始化:
4. 填表顺序:
5. 返回值:
代码编写:
总结:
总结不易~本章节对我的收获很大,希望对你也是~!!!
动态规划_两个数组的 dp (含字符串数组)
经过前面一系列动态规划的学习,我相信对这一部分已经有了充分较为完整的理解,接下来是对两个数组的 dp (含字符串数组)分支的继续学习~
1. 最⻓公共⼦序列(medium)

解析:
1. 状态表⽰:
dp[i][j] 表⽰: s1 的 [0, i] 区间以及 s2 的 [0, j] 区间内的所有的⼦序列中,最⻓公共⼦序列的⻓度。
2. 状态转移⽅程:
i. 两个字符相同, s1[i] = s2[j] :那么最⻓公共⼦序列就在 s1 的 [0, i - 1] 以及 s2 的 [0, j - 1] 区间上找到⼀个最⻓的,然后再加上 s1[i] 即可。因此dp[i][j] = dp[i - 1][j - 1] + 1;
ii. 两个字符不相同, s1[i] != s2[j] :那么最⻓公共⼦序列⼀定不会同时以 s1[i]和 s2[j] 结尾。那么我们找最⻓公共⼦序列时,有下⾯三种策略:• 去 s1 的 [0, i - 1] 以及 s2 的 [0, j] 区间内找:此时最⼤⻓度为 dp[i - 1][j] ;• 去 s1 的 [0, i] 以及 s2 的 [0, j - 1] 区间内找:此时最⼤⻓度为 dp[i ][j - 1] ;• 去 s1 的 [0, i - 1] 以及 s2 的 [0, j - 1] 区间内找:此时最⼤⻓度为 dp[i - 1][j - 1] 。

if(s1[i] == s2[j]) dp[i][j] = dp[i - 1][j - 1] + 1 ;if(s1[i] != s2[j]) dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) 。
3. 初始化:
a. 「空串」是有研究意义的,因此我们将原始 dp 表的规模多加上⼀⾏和⼀列,表⽰空串。b. 引⼊空串后,⼤⼤的⽅便我们的初始化。c. 但也要注意「下标的映射关系」,以及⾥⾯的值要「保证后续填表是正确的」。
4. 填表顺序:
5. 返回值:
代码编写:
class Solution {
public:int longestCommonSubsequence(string s1, string s2) {int n=s1.size(),m=s2.size();s1=" "+s1;s2=" "+s2;vector<vector<int>> dp(n+1,vector<int>(m+1));int ret=0;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(s1[i]==s2[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[n][m];}
};
总结:
对于两个数组dp问题,通过这一道模板题就有很好的理解,最重要的还是定义状态转移方程,熟悉这一题的套路就是求出两个字符串的最长公共子序列的长度是通过s1[0,i] 和 s2[0,j]这两个子串的范围来获得的,在一个二维dp内能够进行表示~
2. 不相交的线(medium)
求两个数组的最长公共子序列的长度
解析:
开始第一眼看这一题的时候,就是要求不相交的线的个数,一下子就被难到了,要求不相交线的个数,那用双指针呢???然后分别遍历两个数组,只要满足不回退就不会相交!但是这样就不能确定遍历一遍后得到的线的个数是否是最多的
但是又仔细一看,这要需要被点一下,只需要你仔细观察一下,是不是就也是在两个数组内求最长的公共子序列问题!那么就简单了,只需要跟上一题一样分析就好啦~

代码编写:
class Solution {
public:int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {//最长公共子序列int n=nums1.size(),m=nums2.size();vector<vector<int>> dp(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]) dp[i][j]=dp[i-1][j-1]+1;else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);}}return dp[n][m];}
};
总结:
需要仔细观察,满足哪种条件,不能硬着头就开始暴力,一定有更优解的办法~
3. 不同的⼦序列(hard)
解析:
1. 状态表⽰:

2. 状态转移⽅程:
3. 初始化:
4. 填表顺序:
5. 返回值:
class Solution {
public:int numDistinct(string s, string t) {int n=t.size(),m=s.size();vector<vector<double>> dp(n+1,vector<double>(m+1));for(int i=0;i<=m;i++)dp[0][i]=1;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(t[i-1]==s[j-1]) dp[i][j]+=dp[i-1][j-1];dp[i][j]+=dp[i][j-1];}}return dp[n][m];}
};
总结:
虽然是困难题,但是还是离不开我们上一题的思路,就是对两个字符串的结尾字符考虑是否存在的问题~
4. 通配符匹配(hard)
解析:
1. 状态表⽰:

2. 状态转移⽅程:

3. 初始化:
4. 填表顺序:
5. 返回值:
代码编写:
class Solution {
public:bool isMatch(string s, string p) {int n=s.size(),m=p.size();vector<vector<bool>> dp(n+1,vector<bool>(m+1));s=" "+s,p=" "+p;dp[0][0]=true;for(int i=1;i<=m;i++){if(p[i]=='*') dp[0][i]=true;else break;}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(p[j]=='*'){dp[i][j]=dp[i][j-1]||dp[i-1][j];}else{if(p[j]=='?'||s[i]==p[j])dp[i][j]=dp[i-1][j-1];}}}return dp[n][m];}
};
总结:
这一题是真正的难题!还需要多加练习,考虑为什么要采用dp[i][j] 表⽰: p 字符串 [0, j] 区间内的⼦串能否匹配字符串 s 的 [0, i] 区间内的⼦串。 这种状态表达,也就是经验+题目要求
5. 正则表达式匹配(hard)

解释:
1. 状态表⽰:
2. 状态转移⽅程:

3. 初始化:
第⼀⾏表⽰ s 是⼀个空串, p 串和空串只有⼀种匹配可能,即 p 串全部字符表⽰为 "任⼀字符 + *",此时也相当于空串匹配上空串。所以,我们可以遍历 p 串,把所有前导为 "任⼀字符 + *" 的 p ⼦串和空串的 dp 值设为 true 。 第⼀列表⽰ p 是⼀个空串,不可能匹配上 s 串,跟随数组初始化即可。
4. 填表顺序:
5. 返回值:
代码编写:
class Solution {
public:bool isMatch(string s, string p) {int n = s.size(),m = p.size();vector<vector<int>> dp(n+1,vector<int>(m+1));p = " " + p, s = " " + s;dp[0][0]=true;for(int i=2;i<=m;i+=2){if(p[i] == '*') dp[0][i]=1;else break;}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(p[j]=='*') dp[i][j]=dp[i][j-2] || (p[j-1] == '.' || p[j-1]==s[i]) && dp[i-1][j];else dp[i][j] = (s[i] == p[j] || p[j] == '.') && dp[i-1][j-1];}}return dp[n][m];}
};
总结:
这一题真的有难度,对于最重要的状态表达式描述好后,状态转移方程和初始化 就是细节问题~对于这一题的状态转移方程会很麻烦,所以一定要话清楚草图和考虑每一个字符前面一个字符出现的各种情况,但是讨论完发现其实也就是两行代码!!!这一题值得多总结,多思考~
6. 交错字符串(medium)

解析:
1. 状态表⽰:
2. 状态转移⽅程:
3. 初始化:
dp[0][j] = s2[j - 1] == s3[j - 1] && dp[0][j - 1] , j 从 1 到 n( n 为 s2 的⻓度)
dp[i][0] = s1[i - 1] == s3[i - 1] && dp[i - 1][0] , i 从 1 到 m( m 为 s1 的⻓度)
4. 填表顺序:
5. 返回值:
代码编写:
class Solution {
public:bool isInterleave(string s1, string s2, string s3) {int n = s1.size(), m = s2.size();if (m + n != s3.size())return false;vector<vector<int>> dp(n + 1, vector<int>(m + 1));s1 = " " + s1;s2 = " " + s2;s3 = " " + s3;dp[0][0] = 1;for (int i = 1; i <= m; i++) {if (s2[i] == s3[i])dp[0][i] = 1;elsebreak;}for (int i = 1; i <= n; i++) {if (s1[i] == s3[i])dp[i][0] = 1;elsebreak;}for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {dp[i][j] = (s1[i] == s3[i + j]) && dp[i - 1][j] ||(s2[j] == s3[i + j]) && dp[i][j - 1];}}return dp[n][m];}
};
总结:
有了上面两题的试炼,这题简直小ks,就只需要考虑清楚状态转移方程是在 || 下进行的就是不要连续用if else 进行判断,再就是初始化这个细节问题,分别考虑s1,s2空串的情况进行初始化填表
7. 两个字符串的最⼩ ASCII 删除和(medium)
解析:
1. 状态表⽰:
2. 状态转移⽅程:

3. 初始化:

4. 填表顺序:
5. 返回值:
代码编写:
class Solution {
public:int minimumDeleteSum(string s1, string s2) {int n=s1.size(),m=s2.size();s1=" "+s1,s2=" "+s2;int ret=0;for(int i=1;i<=n;i++) ret+=(s1[i]);for(int i=1;i<=m;i++) ret+=(s2[i]);vector<vector<int>> dp(n+1,vector<int>(m+1));for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(s1[i]==s2[j]) dp[i][j] = dp[i-1][j-1]+(s2[j]);else dp[i][j]=max(dp[i][j],max(dp[i][j-1],dp[i-1][j]));}}ret-=2*dp[n][m];return ret;}
};
总结:
这一题要我们求出删除最小的字符的ASCII值,让两个字符串相等,如果真的顺着题目往下想,还真的挺难,要考虑的情况好多,但是但凡反着思考一下:我们只要求出最大的公共子序列ASCII值就能直到最小值,并且我们前面也做过一样的求最大公共子序列的问题,所以还是很轻松的~
8. 最⻓重复⼦数组(medium)

解析:
1. 状态表⽰:
2. 状态转移⽅程:
3. 初始化:
4. 填表顺序:
5. 返回值:
代码编写:
class Solution {
public:int findLength(vector<int>& nums1, vector<int>& nums2) {int n = nums1.size(), m = nums2.size();vector<vector<int>> dp(n+1,vector<int>(m+1));int ret=0;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(nums1[i-1]==nums2[j-1]) dp[i][j] = dp[i-1][j-1] + 1;ret=max(ret,dp[i][j]);}}return ret;}
};
总结:
有过前面子数组和子序列的总结,我觉得我自身是得到了质的飞跃~,现在再看这种题也已是题中人了嘿嘿嘿,加油!
总结不易~本章节对我的收获很大,希望对你也是~!!!
相关文章:

专题二十五_动态规划_两个数组的 dp (含字符串数组)_算法专题详细总结
目录 动态规划_两个数组的 dp (含字符串数组) 1. 最⻓公共⼦序列(medium) 解析: 1. 状态表⽰: 2. 状态转移⽅程: 3. 初始化:编辑 4. 填表顺序:编辑 5. 返回值…...

PHP语法学习(第七天)-循环语句,魔术常量
老套路了,朋友们,先回忆昨天讲的内容PHP语法学习(第六天)主要讲了PHP中的if…else语句、关联数组以及数组排序。 想要学习更多PHP语法相关内容点击“PHP专栏!” 下列代码都是在PHP在线测试运行环境中得到的!! 还记得电…...
数据库授权讲解一下
这条 SQL 命令是 MySQL 数据库中用于权限管理的 GRANT 语句。它用于授予用户特定的权限。下面是命令的详细解释: GRANT ALL PRIVILEGES ON *.* TO root% IDENTIFIED BY Zz!12345678 WITH GRANT OPTION;GRANT: 这是一个关键字,用于…...

组件开发的环境准备: nodejs安装,npm镜像源的修改,pnpm包管理器的安装(全局安装),基于pnpm创建脚手架项目
Node.js 是一个开源的、跨平台的 JavaScript 运行环境(本质是Chrome引擎的封装),允许开发者使用 JavaScript 来编写服务器端代码 npm(Node Package Manager)是 Node.js 包管理器, 用来安装各种库、框架和工具 【Node.js官网】 https://nodejs.org 【n…...
学生成绩统计系统
实验内容 问题描述: 输入n个学生的考试成绩,每个学生信息由姓名与分数组成;试设计一种算法: (1)按分数高低次序,打印出每个学生的名次,分数相同的为同一名次; (2)按名次输出每个学生的姓名与分数。 基本要求: (1)学生的考试成绩必须通过…...

【Spring项目】图书管理系统
阿华代码,不是逆风,就是我疯 你们的点赞收藏是我前进最大的动力!! 希望本文内容能够帮助到你!! 目录 一:项目实现准备 1:需求 (1)登录 2:准备…...

Vivado ILA数据导出MATLAB分析
目录 ILA数据导出 分析方式一 分析方式二 有时候在系统调试时,数据在VIVADO窗口获取的信息有限,可结合MATLAB对已捕获的数据进行分析处理 ILA数据导出 选择信号,单击右键后,会有export ILA DATA选项,将其保存成CS…...

【开源免费】基于SpringBoot+Vue.JS高校学科竞赛平台(JAVA毕业设计)
博主说明:本文项目编号 T 075 ,文末自助获取源码 \color{red}{T075,文末自助获取源码} T075,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…...

【机器学习】——windows下安装anaconda并在vscode上进行配置
一、安装anaconda 1.进入清华的镜像网站,下载自己电脑对应的anaconda版本。网站:https://repo.anaconda.com/archive/ 这里我下载的版本是anaconda3-2024.10-1-Windows-x86-64 2.下载完毕后开始安装anaconda 3.配置anaconda环境变量 在设置中找到编…...

【H2O2|全栈】Node.js与MySQL连接
目录 前言 开篇语 准备工作 初始配置 创建连接池 操作数据库 封装方法 结束语 前言 开篇语 本节讲解如何使用Node.js实现与MySQL数据库的连接,并将该过程进行函数封装。 与基础部分的语法相比,ES6的语法进行了一些更加严谨的约束和优化&#…...

汽配行业数字化解决方案(一)
汽配行业数字化解决方案,是通过整合云计算、大数据、人工智能、物联网等先进技术,构建一个全面、高效、智能的数字化生态系统,以实现汽配供应链的全程可视化与智能化管理。该解决方案涵盖了从供应商管理、库存优化、订单处理、物流跟踪到客户…...

前端路径“@/“的使用和配置
环境:vitets 需要安装types/node npm install types/node --save-dev在tsconfig.json中添加 如果有tsconfig.app.json和tsconfig.node.json文件,则在app.json中添加 "compilerOptions": {"baseUrl":".","paths&q…...

动态规划子序列问题系列一>最长递增子序列
题目: 解析: 代码: public int lengthOfLIS(int[] nums) {int n nums.length;int[] dp new int[n];int ret 1;//最坏情况为1//初始化for(int i 0; i < n; i) dp[i] 1;for(int i 1; i < n; i){for(int j 0; j < i-1; j)if(…...
链表头文件大更新!!!
引言 原文章:链表简介及自制链表操作头文件_自己写一个链表头文件-CSDN博客。 此次更新添加了更多功能,让改头文件更 人性化 。 安装教程见原文章。 介绍 linked_list.h 头文件 linked_list.h 是一个 C 头文件,定义了一个模板类 LinkedListÿ…...

力扣3381.长度可被K整除的子数组的最大元素和
力扣3381.长度可被K整除的子数组的最大元素和 题目 题目解析及思路 题目要求返回一段长度为K的倍数的最大子数组和 同余前缀和 代码 class Solution { public:long long maxSubarraySum(vector<int>& nums, int k) {int n nums.size();vector<long long>…...
http.ServeMux多路复用器的设置
package mainimport ("fmt""net/http" )func first(w http.ResponseWriter, r *http.Request) {fmt.Fprintln(w, "多函数-first") }func second(w http.ResponseWriter, r *http.Request) {fmt.Fprintln(w, "多函数-second") }func ma…...

优化器与优化方法:在现代科学与工程中的应用
目录 编辑 优化器:机器学习中的参数调整 1. 梯度下降系列 2. 动量法(Momentum) 3. Adagrad 4. RMSprop 5. Adam 优化方法:寻找系统最优解 线性规划 非线性规划 凸优化 非凸优化 结论 在当今的科学和工程领域&#…...

笔记本外接显示屏没声音
1、笔记本正常有声音,但是外接显示屏后没有声音了怎么回事呢?原来外接显示屏后笔记本的声音输出会自动选择显示屏的音频输出,但是显示屏可能没有声音输出所以导致笔记本没有声音。 2、解决办法:打开笔记本设置,选择声…...
vue框架
Vue.js是一种用于构建用户界面的JavaScript框架。它是一个轻量级框架,被设计为逐渐采用的渐进式框架,可以与现有项目集成,也可以作为一个完整的单页应用程序框架使用。 Vue.js具有以下特点: 简单易学:Vue.js的API简单…...

Vue指令(一)--v-html、v-show、v-if、v-else、v-else-if、v-on、v-bind、v-for、v-model
目录 (一)初识指令和内容渲染指令v-html 1.v-html 案例: 官网的API文档 (二)条件渲染指令v-show和v-if 1. v-show 2. v-if (三)条件渲染指令v-else和v-else-if 案例 (四…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...

回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...