【Day38 LeetCode】动态规划DP 子序列问题Ⅱ

server/2025/2/13 7:01:29/

一、动态规划DP 子序列问题Ⅱ

1、leetcode.cn/problems/longest-common-subsequence/description/" rel="nofollow">最长公共子序列 1143

确定dp数组含义,dp[i][j]表示长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列的长度。
dp转移关系,对于当前值dp[i][j], 分为text1[i - 1] 与 text2[j - 1]相同与不相同两种情况。text1[i - 1] 与 text2[j - 1]相同时,这两个字符可以作为最长公共子序列的一部分, d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 dp[i][j] = dp[i-1][j-1] + 1 dp[i][j]=dp[i1][j1]+1;text1[i - 1] 与 text2[j - 1]不同时,从不要text1[i-1]或者text2[j-1]中选取最大值, d p [ i ] [ j ] = m a x ( d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j ] ) dp[i][j] = max(dp[i][j-1], dp[i-1][j]) dp[i][j]=max(dp[i][j1],dp[i1][j])
边界的初始值都为0,因为还没有公共子序列。

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];}
};

从递推公式来看,当前的dp值dp[i][j]只与上方、左方和左上方的值有关,可以进一步优化空间复杂度。只与上方和左方有关,之前的博客介绍过优化的写法,这题多了一个左上方的值,如果只采用一维数组,那么左上方的值会被左方的值更新替代,所以需要额外的变量来存储和更新当前值的左上方值
同时,将二维数组优化成一维数组时,还需要注意边界和初始化的问题。

class Solution {
public:int longestCommonSubsequence(string text1, string text2) {int m = text1.size(), n = text2.size();vector<int> dp(n + 1);for(int i=1; i<=m; ++i){int leftup = dp[0];for(int j=1; j<=n; ++j){int tmp = dp[j];if(text1[i-1]==text2[j-1]){dp[j] = leftup + 1;}else{dp[j] = max(dp[j], dp[j-1]);}leftup = tmp;}}return dp[n];}
};

2、leetcode.cn/problems/uncrossed-lines/description/" rel="nofollow">不相交的线 1035

这题也是有两个容器,只不过由字符串变成了整型数组。仍可套用相似的dp数组定义。
对于递推关系的推导,也可分为nums1[i-1]与nums2[j-1]相同和不相同,对于相同的情况,这两个数可以画一条线,所以 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 dp[i][j] = dp[i-1][j-1] + 1 dp[i][j]=dp[i1][j1]+1;对于不同的情况,这两明确不能画线,则可以从dp[i-1][j]、dp[i][j-1]取最大值,的 d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) dp[i][j] = max(dp[i-1][j], dp[i][j-1]) dp[i][j]=max(dp[i1][j],dp[i][j1])。可以发现,递推公式与上一题也一样。
初始化也是,边界都初始化为0,因为不能画出线。
代码如下,这题和上一题可以说是一模一样。

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;elsedp[i][j] = max(dp[i-1][j], dp[i][j-1]);}}return dp[m][n];}
};

空间复杂度优化也是一样的,甚至代码都一模一样,就不赘述了。

3、leetcode.cn/problems/maximum-subarray/description/" rel="nofollow">最大子数组和 53

dp数组dp[i]表示下标0~i(以nums[i]为结尾)的最大连续子序列和,递推公式为 d p [ i ] = m a x ( n u m s [ i ] , n u m s [ i ] + d p [ i − 1 ] ) dp[i] = max(nums[i], nums[i] + dp[i-1]) dp[i]=max(nums[i],nums[i]+dp[i1])

class Solution {
public:int maxSubArray(vector<int>& nums) {int n = nums.size();vector<int> dp(n);dp[0] = nums[0];int ans = nums[0];for(int i=1; i<n; ++i){dp[i] = max(nums[i], nums[i] + dp[i-1]);ans = max(ans, dp[i]);}return ans;}
};

发现当前值dp[i]只与dp[i-1]有关,所以可以只采用变量来替代数组,优化空间复杂度,代码如下:

class Solution {
public:int maxSubArray(vector<int>& nums) {int ans = nums[0], cur = nums[0];for(int i=1; i<nums.size(); ++i){cur = max(nums[i], nums[i] + cur);ans = max(ans, cur);}return ans;}
};

4、leetcode.cn/problems/is-subsequence/description/" rel="nofollow">判断子序列 392

有两个字符串,想到dp数组含义dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度。
递推公式,对于当前dp[i][j],分为s[i-1]与t[j-1]相等和不相等两种情况。当s[i-1]==t[j-1],则 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] dp[i][j] = dp[i-1][j-1] dp[i][j]=dp[i1][j1];当s[i-1]!=t[j-1]时,需要将这个不等的元素删掉, d p [ i ] [ j ] = d p [ i ] [ j − 1 ] dp[i][j] = dp[i][j-1] dp[i][j]=dp[i][j1]

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));for(int i=0; i<=n; ++i)dp[0][i] = 1;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];}else{dp[i][j] = dp[i][j-1];}}}return dp[m][n];}
};
class Solution {
public:bool isSubsequence(string s, string t) {int m = s.size(), n = t.size();vector<int> dp(n+1, 1);for(int i=1; i<=m; ++i){int leftup = dp[0];dp[0] = 0;for(int j=1; j<=n; ++j){int tmp = dp[j];if(s[i-1] == t[j-1]){dp[j] = leftup;}else{dp[j] = dp[j-1];}leftup = tmp;}}return dp[n];}
};

也可以采用双指针的方法,使用两个指针指向两个字符串,子序列的指针碰到相等的值才移动,空间复杂度更低。

class Solution {
public:bool isSubsequence(string s, string t) {int n = s.size();int j = 0; // 指向s的指针for(int i=0; i<t.size(); ++i){if(t[i] == s[j])++j;if(j==n)return true;}return n==0;}
};

二、写在后面

子序列问题的递推关系比较好推导,当涉及到两个数组或者字符串时,通常要采用二维dp数组,同时也要考虑如何优化空间复杂度,看能否将二维数组优化成一维数组,这个问题的关键是理清递推公式当前值与其它值的位置关系,是否是固定的位置关系,然后需要注意边界值的初始化这些细节


http://www.ppmy.cn/server/167264.html

相关文章

PhotoShop中创建窗口使用对应按钮创建对应图层简单示例

以前在使用Photoshop的PSD文件转换成Unity的UI Prefab工具的时候&#xff0c;想过是否能在PhotoShop中创建“组件”方式创建层&#xff0c;然后通过代码给层做重命名&#xff0c;不需要手动改写层的名字&#xff0c;可以直接创建所需数量的图层并按照层级排列&#xff0c;具体思…

大模型deepseek-r1 本地快速搭建

1、安装部署ollama 详细步骤见&#xff1a;Ollama 下载和安装 官网下载地址&#xff1a;Ollama官网 2、大模型Deepseekk-r1下载 详细步骤见&#xff1a;大模型deepseek-r1 本地ollama部署详解 ollama run deepseek-r13、Open WebUI部署详解 详细见步骤&#xff1a;大模型d…

DeepSeek+图生生:电商制作商品图的高效方案,适合大众生图的AI工具

在电商红海竞争中&#xff0c;商品视觉呈现已成为流量争夺的核心战场。然而&#xff0c;传统拍摄模式面临多重瓶颈&#xff0c;成本高昂、效率低下等。 而DeepSeek与图生生的结合使用&#xff0c;正以“AI提示词智能生图”的协作模式&#xff0c;为商家提供零成本、分钟级、高…

蓝桥杯---N字形变换(leetcode第6题)题解

文章目录 1.问题重述2.例子分析3.思路讲解4.代码分析 1.问题重述 这个题目可以是Z字形变换&#xff0c;也可以叫做N字形变换&#xff1a; 给定我们一串字符&#xff0c;我们需要把这串字符按照先往下写&#xff0c;再往右上方去写&#xff0c;再往下去写&#xff0c;再往右上…

Python使用OpenCV图片去水印多种方案实现

1. 前言 本文为作者学习记录&#xff0c;使用Python结合OpenCV&#xff0c;总结了几种常见的水印去除方式&#xff0c;简单图片去水印效果良好&#xff0c;但是复杂图片有点一言难尽&#xff0c;本文部分代码仅供参考&#xff0c;并不能针对所有水印通用&#xff0c;需要根据具…

人生的转折点反而迷失了方向

就像我老婆说的&#xff0c;我是抽空结了一个婚。今天是上班的第三天&#xff0c;不知道是出于何种原因&#xff0c;自己反而陷入了深深的困境&#xff0c;没有了斗志&#xff0c;原因也找不出来&#xff0c;白天在公司没有很大量的产出&#xff0c;晚上回去是想学一学&#xf…

leetcode 移除元素

题目 题解 1、双指针 // 时间复杂度&#xff1a;O(n) // 空间复杂度&#xff1a;O(1) class Solution { public:int removeElement(vector<int>& nums, int val) {int slowIndex 0;for (int fastIndex 0; fastIndex < nums.size(); fastIndex) {if (val ! num…

防火墙是什么?详解网络安全的关键守护者

当今信息化时代&#xff0c;企业和个人在享受数字生活带来的便利时&#xff0c;也不可避免地面对各种潜在的风险。防火墙作为网络安全体系中的核心组件&#xff0c;就像一道牢不可破的防线&#xff0c;保护着我们的数据和隐私不受外界威胁的侵害。那么防火墙是什么&#xff1f;…