两个数组的dp问题

news2024/12/24 9:13:29

目录

最长公共子序列

不相交的线

不同的子序列

通配符匹配

正则表达式匹配

交错字符串

两个字符串的最小ASCII删除和

最长重复子数组


声明:接下来主要使用动态规划来解决问题!!!

最长公共子序列

题目

思路

根据经验+题目要求,我们将屡试不爽的采用“以某个位置”为结尾来分析问题。

状态表示:dp[i][j]表示字符串1的[0,i]区间和字符串2的[0,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]).

初始化:不用初始化。

填表顺序:从左往右。

返回值:dp[m][n].

代码

class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        int m=text1.size(),n=text2.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(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[m][n];
    }
};





//或者下面的




class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        int m=text1.size(),n=text2.size();
        vector<vector<int>> dp(m+1,vector<int>(n+1));
        text1=' '+text1;
        text2=' '+text2;
        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];
    }
};
不相交的线

题目

思路

以例2为例,

通过观察不难发现,实则是找两个数组的最长公共子数组,与上一道题最长公共子序列如出一辙。

根据经验+题目要求,我们将屡试不爽的采用“以某个位置”为结尾来分析问题。

状态表示:dp[i][j]表示数组1的[0,i]区间和数组2的[0,j]区间内的所有公共子数组的最长的长度.

状态转移方程:if(nums1[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]).

初始化:不用初始化。

填表顺序:从左往右。

返回值: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];
    }
};
不同的子序列

题目

思路

根据经验+题目要求,我们将屡试不爽的采用“以某个位置”为结尾来分析问题。

状态表示:dp[i][j]表示s[0,i]区间内有多少种t[0,j]区间字符串。

状态转移方程:dp[i][j]=dp[i-1][j]+dp[i-1][j-1]【后者必须满足s[i]==t[j]】

初始化:dp[i][0]=1,第一列全都初始化为1.

返回值:dp[m][n].

代码

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




//或者下面的代码




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

题目

思路

根据经验+题目要求,我们将屡试不爽的采用“以某个位置”为结尾来分析问题。

状态表示:dp[i][j]表示字符串p[0,j]区间字符串是否能匹配字符串s[0,i]区间字符串。

针对p[j]=='*',化简

【1】数学方法

【2】分析法

可以先让'*’匹配一个s字符串末尾字符,但是不消掉'*'

状态转移方程:

                if(p[j-1]!='*') dp[i][j]=(p[j-1]=='?' || p[j-1]==s[i-1]) && dp[i-1][j-1];

                else dp[i][j]=dp[i-1][j] || dp[i][j-1];

初始化:

第一列除去[0,0]位置之外全都为fasle,

第一行除去[0,0]位置之外,初始化规则:当字符串p[0,j]区间含不为'*'字符,后边都为false,否则为true.

填表顺序:从上往下,从左往右。

返回值:dp[m][n].

代码

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



//或者为下面的代码



class Solution {
public:
    bool isMatch(string s, string p) {
        int m=s.size(),n=p.size();
        vector<vector<bool>> dp(m+1,vector<bool>(n+1));
        // dp[0][0]=true;
        for(int i=0;i<=n;i++){
            bool flag=true;
            for(int j=0;j<i;j++){
                if(p[j]!='*') flag=false;
            }
            dp[0][i]=flag;
        }
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++){
                if(p[j-1]==s[i-1]) dp[i][j]=dp[i-1][j-1];
                else if(p[j-1]=='?') dp[i][j]=dp[i-1][j-1];
                else if(p[j-1]=='*') dp[i][j]=dp[i-1][j] || dp[i][j-1];
            }
        return dp[m][n];
    }
};
正则表达式匹配

题目

思路

根据经验+题目要求,我们将屡试不爽的采用“以某个位置”为结尾来分析问题。

状态表示:dp[i][j]表示字符串p[0,j]区间字符串是否能匹配字符串s[0,i]区间字符串。

针对p[j]=='*',化简

【1】数学方法

【2】分析法

可以先让'*’和前一个字符匹配一个s字符串末尾字符,但是不消掉'*'和前一个字符

状态转移方程:

                if(p[j-1]=='*') dp[i][j]=((p[j-2]==s[i-1] || p[j-2]=='.') && dp[i-1][j]) || dp[i][j-2];

                else dp[i][j]=(p[j-1]=='.' || p[j-1]==s[i-1]) && dp[i-1][j-1];

初始化:

第一列除去[0,0]位置之外全都为fasle,

第一行除去[0,0]位置之外,初始化规则:当字符串p[0,j]区间偶数位置都为'*'字符,则为false,其余位置为false,否则之后都为true.

填表顺序:从上往下,从左往右。

返回值:dp[m][n].

代码

class Solution {
public:
    bool isMatch(string s, string p) {
        int m=s.size(),n=p.size();
        vector<vector<bool>> dp(m+1,vector<bool>(n+1));
        dp[0][0]=true;
        for(int i=2;i<=n;i+=2){
            if(p[i-1]=='*') dp[0][i]=true;
            else break;
        }
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                if(p[j-1]=='*') dp[i][j]=((p[j-2]==s[i-1] || p[j-2]=='.') && dp[i-1][j]) || dp[i][j-2];
                else dp[i][j]=(p[j-1]=='.' || p[j-1]==s[i-1]) && dp[i-1][j-1];
            }
        }
        return 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=2;i<=n;i+=2){
            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]=((p[j-1]==s[i] || p[j-1]=='.') && dp[i-1][j]) || dp[i][j-2];
                else dp[i][j]=(p[j]=='.' || p[j]==s[i]) && dp[i-1][j-1];
            }
        }
        return dp[m][n];
    }
};
交错字符串

题目

思路

根据经验+题目要求,我们将屡试不爽的采用“以某个位置”为结尾来分析问题。

为了便于表述,在s1,s2,s3每个字符串的最前边增加一个空格。

状态表示:dp[i][j]表示字符串s1[1,i]区间和字符串s2[1,j]区间能否凑成字符串s3的[1,i+j]区间。

状态转移方程:

初始化:

初始化第一行规则:依次判断字符串s2和s3对应位置是否相等,相等则为true,否则为false并break.

初始化第一列规则:依次判断字符串s1和s3对应位置是否相等,相等则为true,否则为false并break.

填表顺序:从上往下,从左往右。

返回值:dp[m][n]。

代码

class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
        int m=s1.size(),n=s2.size();
        if(m+n!=s3.size()) return false;
        s1=' '+s1;
        s2=' '+s2;
        s3=' '+s3;
        vector<vector<bool>> dp(m+1,vector<bool>(n+1));
        for(int i=0;i<=m;i++)
            if(s1[i]==s3[i]) dp[i][0]=true;
            else break;
        for(int i=0;i<=n;i++)
            if(s2[i]==s3[i]) dp[0][i]=true;
            else break;
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                dp[i][j]=(s1[i]==s3[i+j] && dp[i-1][j]) || (s2[j]==s3[i+j] && dp[i][j-1]);
            }
        }
        return dp[m][n];
    }
};
两个字符串的最小ASCII删除和

题目

思路

根据经验+题目要求,我们将屡试不爽的采用“以某个位置”为结尾来分析问题。

题目中是求两个字符串的最小ASCII删除和,若直接求两个字符串的最小ASCII删除和有点麻烦,采用“正难则反”的思想,由于字符串时确定的,即两个字符串的ASCII值总和是确定的,那么只需要求出两个字符串的所有公共子序列中ASCII值最大的子序列,用sum-2*公共子序列ASCII最大值即可。

状态表示:dp[i][j]表示字符串s1[0,i]区间和字符串s2[0,j]区间所有的公共子序列中ASCII总和最大的值。

状态转移方程:

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

                if(s1[i-1]==s2[j-1])

                    dp[i][j]=max(dp[i][j],dp[i-1][j-1]+s1[i-1]);

初始化:不用初始化。

填表顺序:从上往下,从左往右。

返回值:ret-2*dp[m][n]。

代码

class Solution {
public:
    int minimumDeleteSum(string s1, string s2) {
        int m=s1.size(),n=s2.size();
        vector<vector<int>> dp(m+1,vector<int>(n+1));
        int ret=0;
        for(char ch:s1)
            ret+=ch;
        for(char ch:s2)
            ret+=ch;
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
                if(s1[i-1]==s2[j-1]) 
                    dp[i][j]=max(dp[i][j],dp[i-1][j-1]+s1[i-1]);
            }
        }
        return ret-2*dp[m][n];
    }
};
最长重复子数组

题目

思路

根据经验+题目要求,我们将屡试不爽的采用“以某个位置”为结尾来分析问题。

如果以区间来分析问题,仔细分析一下会发现是错误的,因为子数组是连续的,而子序列可以连续也可以不连续,那么我们将以某个位置为结尾来分析问题。

状态表示:dp[i][j]表示数组nums1[0,i]和数组nums2[0,j]区间的所有重复子数组中的最长的长度。

状态转移方程:

初始化:不用初始化。

填表顺序;从上往下,从左往右。

返回值:dp表最大值。

代码

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        int m=nums1.size(),n=nums2.size();
        vector<vector<int>> dp(m+1,vector<int>(n+1));
        int ret=0;
        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,ret=max(ret,dp[i][j]);
            }
        }
        return ret;
    }
};

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

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

相关文章

项目笔记| 基于Arduino和IR2101的无刷直流电机控制器

本文介绍如何使用 Arduino UNO 板构建无传感器无刷直流 &#xff08;BLDC&#xff09; 电机控制器或简单的 ESC&#xff08;电子速度控制器&#xff09;。 无刷直流电机有两种类型&#xff1a;有传感器和无传感器。有感无刷直流电机内置3个霍尔效应传感器&#xff0c;这些传感…

宝塔SSL续签失败

我有2个网站a和b&#xff08;文字中用baidu.com替换我的域名&#xff09; b是要续签那个&#xff0c;但续签报错&#xff1a; nginx version: nginx/1.22.1 nginx: [emerg] host not found in upstream "github.com" in /www/server/panel/vhost/nginx/proxy/a.bai…

【Redis进阶】事务

1. Redis与MySQL的事务差别 相信一谈到事务&#xff0c;大家马上就能联想到MySQL的事务&#xff0c;其事务具有ACID四大特性&#xff0c;但是Redis的事务相比较于MySQL&#xff0c;那就是个"弟中弟"&#xff0c;下面我们就来简单对比两者的事务特性&#xff1a; 原…

用神经网络求解微分方程

微分方程是物理科学的主角之一&#xff0c;在工程、生物、经济甚至社会科学中都有广泛的应用。粗略地说&#xff0c;它们告诉我们一个量如何随时间变化&#xff08;或其他参数&#xff0c;但通常我们对时间变化感兴趣&#xff09;。我们可以了解人口、股票价格&#xff0c;甚至…

【Java面向对象】二进制I/O

文章目录 1.二进制文件2.二进制 I/O 类2.1 FileInputStream 和 FileOutputStream2.2 FilterInputStream和 FilterOutputStream2.3 DatalnputStream 和 DataOutputStream2.4 BufferedInputStream 和 BufferedOutputStream2.5 ObjectInputStream 和 ObjectOutputStream 2.6 Seria…

深入理解 Linux Zero-copy 原理与实现策略图解

用户态和内核态 一般来说&#xff0c;我们在编写程序操作 Linux I/O 之时十有八九是在用户空间和内核空间之间传输数据&#xff0c;因此有必要先了解一下 Linux 的用户态和内核态的概念。 从宏观上来看&#xff0c;Linux 操作系统的体系架构分为用户态和内核态&#xff08;或者…

昇思25天学习打卡营第24天|ResNet50迁移学习

课程打卡凭证 迁移学习 迁移学习是机器学习中一个重要的技术&#xff0c;通过在一个任务上训练的模型来改善在另一个相关任务上的表现。在深度学习中&#xff0c;迁移学习通常涉及在一个大型数据集&#xff08;如ImageNet&#xff09;上预训练的模型上进行微调&#xff0c;以便…

设计模式之策略模式_入门

前言 最近接触了优惠券相关的业务&#xff0c;如果是以前&#xff0c;我第一时间想到的就是if_else开始套&#xff0c;这样的话耦合度太高了&#xff0c;如果后期添加或者删除优惠券&#xff0c;必须直接修改业务代码&#xff0c;不符合开闭原则&#xff0c;这时候就可以选择我…

vue3.0学习笔记(一)——vue3简介与vite脚手架的使用

1. 为什么学vue3 Vue3现状&#xff1a; vue-next 2020年09月18日&#xff0c;正式发布vue3.0版本。但是由于刚发布周边生态不支持&#xff0c;大多数开发者处于观望。现在主流组件库都已经发布了支持vue3.0的版本&#xff0c;其他生态也在不断地完善中&#xff0c;这是趋势。…

Python | Leetcode Python题解之第268题丢失的数字

题目&#xff1a; 题解&#xff1a; class Solution:def missingNumber(self, nums: List[int]) -> int:n len(nums)total n * (n 1) // 2arrSum sum(nums)return total - arrSum

Qt第十三章 目录和文件操作

目录和文件操作 文章目录 目录和文件操作设备I/O简介I/O设备的类型基本文件读写QFileQTemporaryFile 流操作QTextStreamQDataStream QFileInfoQDirQFileSystemWatcherQStandardPathsQSettings 设备I/O 简介 I/O设备的类型 基本文件读写 QFile QFile file("C:/Users/PV…

Cisco 路由重发布 —— 实现路由信息在不同路由域间的传递

一、技术背景 在实际的组网中&#xff0c;可能会遇到这样一个场景&#xff1a;在一个网络中同时存在两种或者两种以上的路由协议。例如客户的网络原先是纯 Cisco 的设备&#xff0c;使用 EIGRP 协议将网络的路由打通。但是后来网络扩容&#xff0c;增加了一批华为的设备&#…

HAL库源码移植与使用之低功耗模式

低功耗特性对用电池供电的产品&#xff1a; 更小电池体积&#xff08;降低了大小和成本&#xff09; 延长电池寿命 电磁干扰更小&#xff0c;提高无线通信质量 电源设计更简单&#xff0c;无需过多考虑散热问题 电源供电区分为&#xff1a; 分为VDD供电区…

平面五杆机构运动学仿真matlab simulink

1、内容简介 略 89-可以交流、咨询、答疑 2、内容说明 略 ] 以 MATLAB 程序设计语言为平台 , 以平面可调五杆机构为主要研究对象 , 给定机构的尺寸参数 , 列出所 要分析机构的闭环矢量方程 , 使用 MATLAB 软件中 SIMULINK 仿真工具 , 在 SIMULINK 模型窗口下建立数…

深入理解TensorFlow底层架构

目录 深入理解TensorFlow底层架构 一、概述 二、TensorFlow核心概念 计算图 张量 三、TensorFlow架构组件 前端 后端 四、分布式计算 集群管理 并行计算 五、性能优化 内存管理 XLA编译 六、总结与展望 深入理解TensorFlow底层架构 一、概述 TensorFlow是一个开…

从0开始的STM32HAL库学习8

PWM控制舵机 配置环境 1. 选择TIM2时钟 2.选择内部时钟模式&#xff0c;打开通道二 3.分频系数PSC:72-1 自动重装寄存器ARR:20000-1 输出比较寄存器 CCR:500~2500( 后面可调整 ) 脉冲选择500后期可以改 编辑代码 调用启动函数 HAL_TIM_PWM_Start(&htim2,TIM_CHANN…

一分钟图情论文:《智慧数据视角下古籍数字出版的创新路径》

由武汉大学的雷珏莹和王晓光合著的《智慧数据视角下古籍数字出版的创新路径研究》论文从智慧数据1的视角出发&#xff0c;探讨了我国古籍数字出版的现状及其发展瓶颈&#xff0c;提出了古籍数字出版在内容、形式、服务和技术四个方面的创新路径。 文中, 研究者首先详细分析了当…

使用Fiddler进行Android和IOS抓包

Android抓包 要使用Telerik Fiddler Classic捕获Android设备的网络流量&#xff0c;您需要执行以下步骤&#xff1a; 在Fiddler Classic上进行设置&#xff1a; 确保已安装并使用BouncyCastle作为证书生成器。较新的Android版本会拒绝有效期超过两年的证书&#xff0c;目前只…

构建本地智能知识问答系统:基于Langchain和ChatGLM的简单实践

在数字化时代&#xff0c;智能知识问答系统成为了提升企业效率和数据安全性的关键工具。本文将介绍如何基于Langchain和ChatGLM构建一个本地化、支持中文的智能知识问答系统。该系统不仅能够实现完全本地化推理&#xff0c;而且对开源模型友好&#xff0c;可满足企业对数据隐私…

Windows中修改pip下载源

目录 一. 打开此电脑或文件管理器&#xff0c;输入 %APPDATA% 回车跳转 二. 在此目录中新建一个文件夹命令为pip 三. 进入这个目录&#xff0c;新建一个pip.ini文件 四. 复制阿里云镜像配置 五. CMD终端下载验证 六. 常用的国内镜像网站 一. 打开此电脑或文件管理器…