leetCode 583.两个字符串的删除操作 动态规划 + 优化空间复杂度(二维dp、一维dp)

583. 两个字符串的删除操作 - 力扣(LeetCode)

给定两个单词 word1 和 word2 ,返回使得 word1 和  word2 相同所需的最小步数

每步 可以删除任意一个字符串中的一个字符。

示例 1:

输入: word1 = "sea", word2 = "eat"
输出: 2
解释: 第一步将 "sea" 变为 "ea" ,第二步将 "eat "变为 "ea"

示例  2:

输入:word1 = "leetcode", word2 = "etco"
输出:4

 一、递归搜索 + 保存计算结果 = 记忆化搜索

  • 二维memo数组 存储计算过的子问题的结果 
class Solution {
public:// 递归搜索 + 保存计算结果 = 记忆化搜索// 二维memo数组 存储过的子问题的结果int minDistance(string s, string t) {int m = s.size(),n = t.size(),memo[m][n]; // 二维memo数组 存储计算过的子问题的结果;memset(memo,-1,sizeof(memo));// -1 表示没有访问过function<int(int,int)> dfs = [&](int i,int j) -> int {if(i<0) //base case 当i指针越界,此时return j+1;if(j<0) //base casereturn i+1;if (memo[i][j] != -1) // memo中有当前遇到的子问题的解,直接拿来返回return memo[i][j];if (s[i] == t[j]) {  memo[i][j] = dfs(i-1, j-1);} else {// memo[i][j] = min(min(dfs(i-1, j)+1,dfs(i, j-1)+1),dfs(i-1, j-1)+2);// memo[i][j] = min(dfs(i-1, j)+1,dfs(i, j-1)+1);memo[i][j] = min(dfs(i-1, j),dfs(i, j-1))+1;}return memo[i][j];};return dfs(m-1,n-1);}
}

二、动态规划 与 递归 的区别 

  • 递归公式 
if (s[i] == t[j]) {  memo[i][j] = dfs(i-1, j-1);
} else {// memo[i][j] = min(min(dfs(i-1, j)+1,dfs(i, j-1)+1),dfs(i-1, j-1)+2);// memo[i][j] = min(dfs(i-1, j)+1,dfs(i, j-1)+1);memo[i][j] = min(dfs(i-1, j),dfs(i, j-1))+1;
}

递归是自上而下调用,子问题自下而上被解决,最后解决了整个问题,而dp是从base case 出发,通过在dp数组记录中间结果,自下而上地顺序地解决子问题

  • dp解法

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

dp[i][j]:以i-1为结尾的字符串word1,和以j-1为结尾的字符串word2,想要达到相等,所需要删除元素的最少次数

2.确定递推公式

if (word1[i - 1] == word2[j - 1]) {dp[i][j] = dp[i - 1][j - 1];
} else {dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
}

3.dp数组初始化

从递推式可看出,dp[i][0] dp[0][j] 是一定要初始化的

  • dp[i][0]:word2为字符串,以 i-1 为结尾的字符串 word1 需要删除 个元素才能变成空串,和word2相同
  • dp[0][j]:word1为字符串,以 j-1 为结尾的字符串 word2 需要删除 个元素才能变成空串,和word1相同
  • dp[0][0]=0,因为两个空字符串相同,删除操作为0
for(int i=1;i<=m;++i) dp[i][0] = i;
for(int j=1;j<=n;++j) dp[0][j] = j;

4.确定遍历顺序

从递推公式 dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1; dp[i][j] = dp[i - 1][j - 1]可以看出dp[i][j]都是根据正上方、正左方推出来的,所以遍历的时候一定是从上到下,从左到右,这样保证dp[i][j]可以根据之前计算出来的数值进行计算。

5.举例推导dp数组

 (1)动态规划 二维dp

class Solution {
public:int minDistance(string word1, string word2) {int m = word1.size(),n = word2.size();vector<vector<int>> dp(m+1,vector<int>(n+1));for(int i=1;i<=m;++i) dp[i][0] = i;for(int j=1;j<=n;++j) dp[0][j] = j;for(int i=1;i<=m;++i) {for(int j=1;j<=n;++j) {if(word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1];// else dp[i][j] = min(min(dp[i-1][j]+1,dp[i][j-1]+1),dp[i-1][j-1]+2);else dp[i][j] = min(dp[i-1][j]+1,dp[i][j-1]+1);}}return dp[m][n];}
};
  • 时间复杂度: O(m * n)
  • 空间复杂度: O(m * n)

(2)动态规划 二维dp 优化空间 

class Solution {
public:  // 动态规划 二维dp 优化空间int minDistance(string word1, string word2) {int m = word1.size(),n = word2.size();// vector<vector<int>> dp(m+1,vector<int>(n+1));vector<vector<int>> dp(2,vector<int>(n+1));for(int j=1;j<=n;++j) dp[0][j] = j;for(int i=1;i<=m;++i) {dp[i%2][0] = i;for(int j=1;j<=n;++j) {if(word1[i-1] == word2[j-1]) dp[i % 2][j] = dp[(i-1)%2][j-1];else dp[i%2][j] = min(dp[(i-1)%2][j]+1,dp[i%2][j-1]+1);}}return dp[m%2][n];}
};
  • 时间复杂度: O(m * n)
  • 空间复杂度: O(n)

(3)动态规划 一维dp(滚动数组) 优化空间

class Solution {
public:  // 动态规划 一维dp(滚动数组) 优化空间int minDistance(string word1, string word2) {int m = word1.size(),n = word2.size();vector<int> dp(n+1);for(int j=1;j<=n;++j) dp[j] = j;for(int i=1;i<=m;++i) {// pre 代表dp[i-1][0]int pre = dp[0];// 初始化当前层的 dp[i][0]dp[0] = i;for(int j=1;j<=n;++j) {int tmp = dp[j];if(word1[i-1] == word2[j-1]) dp[j] = pre;else dp[j] = min(dp[j]+1,dp[j-1]+1);pre = tmp;}}return dp[n];}
};
  • 时间复杂度: O(m * n)
  • 空间复杂度: O(n)

本题除了这种解法外,还有这种解题思路:先求出最长公共子序列,然后 word1.size() + word2.size() - 两倍的最长公共子序列

求最长公共子序列,可以看我往期的这篇文章:leetCode 1143.最长公共子序列

(1)二维dp 

class Solution {
public: int minDistance(string word1, string word2) {int m = word1.size(),n = word2.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(word1[i-1] == word2[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 m + n - 2 * dp[m][n];}
};
  • 时间复杂度: O(m * n)
  • 空间复杂度: O(m * n)

(2)二维dp:优化空间 

class Solution {
public:  // 方法二 二维dp 优化空间int minDistance(string word1, string word2) {int m = word1.size(),n = word2.size();vector<vector<int>> dp(2,vector<int>(n+1)); for(int i=1;i<=m;++i) {for(int j=1;j<=n;++j) {if(word1[i-1] == word2[j-1]) dp[i%2][j] = dp[(i-1)%2][j-1] + 1;else dp[i%2][j] = max(dp[(i-1)%2][j],dp[i%2][j-1]);}}return m + n - 2 * dp[m%2][n];}
};
  • 时间复杂度: O(m * n)
  • 空间复杂度: O(n)

(3)一维dp:优化空间

class Solution {
public:// 方法二 一维dp 优化空间int minDistance(string word1, string word2) {int m = word1.size(),n = word2.size();vector<int> dp(n+1); for(int i=1;i<=m;++i) {int pre = dp[0];for(int j=1;j<=n;++j) {int tmp = dp[j];if(word1[i-1] == word2[j-1]) dp[j] = pre + 1;else dp[j] = max(dp[j],dp[j-1]);pre = tmp;}}return m + n - 2 * dp[n];}
};
  • 时间复杂度: O(m * n)
  • 空间复杂度: O(n)

参考和推荐文章、视频:

代码随想录 (programmercarl.com)

动态规划之子序列,还是为了编辑距离做铺垫 | LeetCode:583.两个字符串的删除操作_哔哩哔哩_bilibili

来自代码随想录课堂的截图:

 

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

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

相关文章

后厂村路灯在线签名网站,在线签名工具,IPA在线签名

IPA在线签名工具网站&#xff0c;在线实现IPA包签名 案例网站&#xff1a;在线签名 - 后厂村路灯https://sign.vx365.vip/ 用户可以自定义签名网站样式。 用户可以独立部署到自己服务器&#xff0c;使用自己的域名。 用户可以使用自己服务器&#xff0c;加快签名速度&#xf…

TypeScript React(上)

目录 扩展学习资料 TypeScript设计原则 TypeScript基础 语法基础 变量声明 JavaScript声明变量 TypeScript声明变量 示例 接口 (标准类型-Interface) 类型别名-Type 接口 VS 类型别名 类型断言:欺骗TS&#xff0c;肯定数据符合结构 泛型、<大写字母> 扩展学习…

Golang 实现接口和继承

小猴子继承了老猴子&#xff0c;这样老猴子拥有的能力包括字段&#xff0c;方法就会自动的被老猴子继承。 小猴子不需要做任何处理就可以拿到老猴子的字段和它的方法&#xff0c;因为是继承关系。 但是小猴子还会其他的技能&#xff0c;比如还会像小鸟一样飞翔&#xff0c;希…

LeetCode34 在排序数组中寻找元素的第一个和最后一个位置

题目&#xff1a; 思路&#xff1a; https://blog.csdn.net/wangjiaqi333/article/details/124526112 直观的思路肯定是从前往后遍历一遍。用两个变量记录第一次和最后一次遇见target的下标&#xff0c;但这个方法的时间复杂度为O(n)&#xff0c;没有利用到数组升序排列的条件…

TensorFlow入门(二十一、softmax算法与损失函数)

在实际使用softmax计算loss时,有一些关键地方与具体用法需要注意: 交叉熵是十分常用的,且在TensorFlow中被封装成了多个版本。多版本中,有的公式里直接带了交叉熵,有的需要自己单独手写公式求出。如果区分不清楚,在构建模型时,一旦出现问题将很难分析是模型的问题还是交叉熵的使…

虹科科技 | 探索CAN通信世界:PCAN-Explorer 6软件的功能与应用

CAN&#xff08;Controller Area Network&#xff09;总线是一种广泛应用于汽车和工业领域的通信协议&#xff0c;用于实时数据传输和设备之间的通信。而虹科的PCAN-Explorer 6软件是一款功能强大的CAN总线分析工具&#xff0c;为开发人员提供了丰富的功能和灵活性。本文将重点…

Swagger3.0 与spring boot2.7x 整合避免swagger2.0与boot2.7冲突

注释掉2.0引入的俩包 直接引入3.0 <dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version></dependency> swagger配置文件粘贴即用哦 import org.springfram…

JVM 性能调优参数

JVM分为堆内存和非堆内存 堆的内存分配用-Xms和-Xmx -Xms分配堆最小内存&#xff0c;默认为物理内存的1/64&#xff1b; -Xmx分配最大内存&#xff0c;默认为物理内存的1/4。 非堆内存分配用-XX:PermSize和-XX:MaxPermSize -XX:PermSize分配非堆最小内存&#xff0c;默认为物理…

【小巧玲珑】文件太大,怎么办?分卷压缩技术了解下,这才是压缩技术

【小巧玲珑】文件太大&#xff0c;怎么办&#xff1f;分卷压缩技术了解下&#xff0c;这才是压缩技术 1、痛点2、场景重现2.1 jar包2.1 ZIP压缩 3、压缩步骤3.1 新建压缩文件3.2 压缩结果 4、解压步骤5、效果6、jar压缩算法 1、痛点 通过浏览器客户端访问云服务&#xff0c;文…

计算机毕业设计选什么题目好?springboot 健身房管理系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

某医疗机构:建立S-SDLC安全开发流程,保障医疗前沿科技应用高质量发展

某医疗机构是头部资本集团旗下专注大健康领域战略性投资与运营的实业公司&#xff0c;市场规模超300亿。该医疗机构已完成数字赋能&#xff0c;形成了标准化、专业化、数字化的疾病和健康管理体系&#xff0c;将进一步规划战略方向&#xff0c;为人工智能纳米技术、高温超导、生…

shiro反序列化和log4j

文章目录 安装环境shiro漏洞验证log4j 安装环境 进入vulhb目录下的weblogic&#xff0c;复现CVE-2018-2894漏洞&#xff1a; cd /vulhub/shiro/CVE-2010-3863查看docker-compose的配置文件&#xff1a; cat docker-compose.yml如图&#xff0c;里面有一个镜像文件的信息和服…