【leetcode】动态规划——序列问题总结

本文内容参考了代码随想录,并进行了自己的总结。

序列问题

不连续序列

300. 最长递增子序列

int n = nums.length;
int[] dp = new int[n];
dp[0] = 1;
for(int i = 1; i < n; i ++ ) {dp[i] = 1; // 每个数字自己是一个子序列for(int j = 0; j < i; j ++ ) {if (nums[i] > nums[j]) { // 严格递增dp[i] = Math.max(dp[j] + 1, dp[i]);}}
}
int res = -1;
for(int i = 0; i < n; i ++ ) res = Math.max(dp[i], res);
return res;

1143. 最长公共子序列

int n = text1.length();
int m = text2.length();
// dp[i][j]: nums1以i-1结尾和nums2中以j-1结尾时的公共最长子序列的长度
int[][] dp = new int[n + 1][m + 1];
for(int i = 1; i <= n; i ++ ) {for(int j = 1; j <= m; j ++ ) {char c1 = text1.charAt(i - 1);char c2 = text2.charAt(j - 1);if (c1 == c2) dp[i][j] = dp[i - 1][j - 1] + 1;else dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);}
}
return dp[n][m];

516. 最长回文子序列

最长公共子序列变体

String s2 = new StringBuffer(s).reverse().toString();
// 求s和s2的最长公共子序列的长度
int n = s.length();
int[][] dp = new int[n + 1][n + 1];
for(int i = 1; i <= n; i ++ ) {for(int j = 1; j <= n; j ++ ) {char c1 = s.charAt(i - 1);char c2 = s2.charAt(j - 1);if (c1 == c2) dp[i][j] = dp[i - 1][j - 1] + 1;else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);} 
}
return dp[n][n];

1035. 不相交的线

最长公共子序列变体

int n = nums1.length;
int m = nums2.length;
// dp[i][j]: nums1以i-1结尾和nums2中以j-1结尾时的公共最长子序列的长度
int[][] dp = new int[n + 1][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] = Math.max(dp[i][j - 1], dp[i - 1][j]); }
}
return dp[n][m];

583. 两个字符串的删除操作

最长公共子序列变体

// 先求最长公共子序列的长度
int n = word1.length();
int m = word2.length();
int[][] dp = new int[n + 1][m + 1];
for(int i = 1; i <= n; i ++ ) {for(int j = 1; j <= m; j ++ ) {char c1 = word1.charAt(i - 1);char c2 = word2.charAt(j - 1);if (c1 == c2) dp[i][j] = dp[i - 1][j - 1] + 1;else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);}
}
return n + m - 2 * dp[n][m];

注意1143. 最长公共子序列和718. 最长重复子数组的区别。

/* 1143. 最长公共子序列 */
int n = text1.length();
int m = text2.length();
// dp[i][j]: nums1以i-1结尾和nums2中以j-1结尾时的公共最长子序列的长度
int[][] dp = new int[n + 1][m + 1];
for(int i = 1; i <= n; i ++ ) {for(int j = 1; j <= m; j ++ ) {char c1 = text1.charAt(i - 1);char c2 = text2.charAt(j - 1);if (c1 == c2) dp[i][j] = dp[i - 1][j - 1] + 1;else dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]); }
}
return dp[n][m]; /* 718. 最长重复子数组 */
int n = nums1.length;
int m = nums2.length;
// dp[i][j]: nums1以i-1结尾和nums2中以j-1结尾时的公共最长子数组的长度
int res = 0;
int[][] dp = new int[n + 1][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;res = Math.max(res, dp[i][j]);}
}
return res;
  1. 为什么要 n+1 和 m+1,而不是 n 和 m?因为在递推式中,会用到 dp[0][0]、dp[0][0~m-1]、dp[0~n-1][0]。取成 n+1 和 m+1 就可以从 [1, n] 和 [1,m] 开始遍历。如果取 n 和 m 的话,就要从 [0, n-1] 和 [0,m-1] 开始遍历,就要单独把 dp[0][0~m-1]、dp[n-1][0] 拿出来考虑,代码会显得比较冗长。
  2. 从题目的区别来说,1143 这个题是求的分开的子序列的长度,718 这个题是球的连续的子序列的长度。
  3. 注意两个区别:
    (1). 递推式中,1143 这个题 c1 != c2 时,会进行递推。而 718 这个题 nums1[i - 1] != nums2[j - 1] 时,不会进行递推,而是直接置为 0。(为什么会这样?具体看 718 上面这个题的总结。)
    (2). 取答案的时候,1143 这个题是直接返回的 dp[n][m],因为取的是分开的公共子序列的最长长度,所以答案一定是会累加到最后的 dp[n][m] 上的。而 718 这个题返回的是 Math.max(dp[i][j]),因为求的时候一旦不连续了就会置为 0,前面计算的连续的长度就不会累加到后面,每个 dp[i][j] 计算的就是断开的几段连续子序列的长度,断开是因为置为 0 了,导致断开了。所以要求答案得时候,就要每个 dp[i][j] 取最大值,即求所有断开的连续子序列的最大长度。

连续序列

718. 最长重复子数组

int n = nums1.length;
int m = nums2.length;
// dp[i][j]: nums1以i-1结尾和nums2中以j-1结尾时的公共最长子数组的长度
int res = 0;
int[][] dp = new int[n + 1][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] = 0;res = Math.max(res, dp[i][j]);}
}
return res;
// ✔ 正确写法
if (nums1[i] == nums2[j]) dp[i][j] = dp[i - 1][j - 1] + 1;
else dp[i][j] = 0;// ❌ 错误写法
if (nums1[i] == nums2[j]) dp[i][j] = dp[i - 1][j - 1] + 1;
else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);

注意第二种写法和第一种写法的区别。我最开始是写的第二种写法,但仔细分析就会发现,这种写法算的实际上是分开的子数组长度,不是连续的子数组长度。因为要保证连续,所以一旦nums1[i] != nums2[j],即当前两个子序列的最后一个数不一样,就说明不连续了, dp[i][j] 就要置为 0,而不是取子序列的长度。

编辑距离

72. 编辑距离

// dp[i][j]: word1前i个字符和word2前j个字符的最短编辑距离/**c1 == c2, 不需要编辑, dp[i][j] = dp[i - 1][j - 1]; c1 != c2, 需要编辑. 编辑分三种情况:(1). 删除, 将word1中, c1删除   (2). 删除, 将word2中, c2删除(3). 替换, 将word1中c1替换成c2由于删除和添加是一样的效果,所以可以选择删除作为操作。*/int n = word1.length();
int m = word2.length();
int[][] dp = new int[n + 1][m + 1];// 初始化:当一个字符串为空的时候,剩下一个字符串要做i/j次操作才能保证二者相同
for(int i = 0; i <= n; i ++ ) dp[i][0] = i;
for(int j = 0; j <= m; j ++ ) dp[0][j] = j;for(int i = 1; i <= n; i ++ ) {for(int j = 1; j <= m; j ++ ) {char c1 = word1.charAt(i - 1);char c2 = word2.charAt(j - 1);if (c1 == c2) dp[i][j] = dp[i - 1][j - 1];else dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;}
}return dp[n][m];

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

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

相关文章

C#计算矩形面积:通过定义结构 vs 通过继承类

目录 一、涉及到的知识点 1.结构 2.结构和类的区别 3.继承 4.使用类继承提高程序的开发效率 5.属性 &#xff08;1&#xff09;属性定义 &#xff08;2&#xff09;get访问器 &#xff08;3&#xff09;set访问器 6. 属性和字段的区别 二、实例&#xff1a;通过定义…

[word] word表格表头怎么取消重复出现? #媒体#笔记#职场发展

word表格表头怎么取消重复出现&#xff1f; word表格表头怎么取消重复出现&#xff1f;在Word中的表格如果过长的话&#xff0c;会跨行显示在另一页&#xff0c;如果想要在其它页面上也显示表头&#xff0c;更直观的查看数据。难道要一个个复制表头吗&#xff1f;当然不是&…

idea:如何连接数据库

1、在idea中打开database: 2、点击 ‘’ ---> Data Source ---> MySQL 3、输入自己的账号和密码其他空白处可以不填&#xff0c;用户和密码可以在自己的mysql数据库中查看 4、最后选择自己需要用的数据库&#xff0c;点击运用ok&#xff0c;等待刷新即可 最后&#xff1a…

springboot179基于javaweb的流浪宠物管理系统的设计与实现

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

disql备份还原

disql备份还原 前言 本文档根据官方文档&#xff0c;进行整理。 一、概述 在 disql 工具中使用 BACKUP 语句你可以备份整个数据库。通常情况下&#xff0c;在数据库实例配置归档后输入以下语句即可备份数据库&#xff1a; BACKUP DATABASE BACKUPSET db_bak_01;语句执行完…

C++进阶(十四)智能指针

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、为什么需要智能指针&#xff1f;二、内存泄漏1、 什么是内存泄漏&#xff0c;内存泄漏的危…

量子位 | 2024年AI还能帮你干什么?这十个趋势必须关注

本文来源公众号“量子位”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;2024年AI还能帮你干什么&#xff1f;这十个趋势必须关注 大年初三&#xff0c;也不要忘记学习&#xff01;新的一年里&#xff0c;怎样能让AI多给自己帮帮…

洛谷 P1182 数列分段 Section II ((Java)

洛谷 P1182 数列分段 Section II &#xff08;(Java) 传送门&#xff1a;P1182 数列分段 Section II 题目&#xff1a;数列分段 Section II 题目描述 对于给定的一个长度为N的正整数数列 A 1 ∼ N A_{1\sim N} A1∼N​&#xff0c;现要将其分成 M M M&#xff08; M ≤ N…

2024,重新出发

我终于回来了QAQ 上次更系统的文章还是在2022呢&#xff0c;看看之前的文章&#xff0c;6个粉丝就开心得不行&#x1f636; 回首向来萧瑟处&#xff0c;归去&#xff0c;也无风雨也无晴。 其实早在2023就发现自己不怎么更文章了&#xff0c;一直在想更&#xff0c;但就……一直…

【数据结构】13:表达式转换(中缀表达式转成后缀表达式)

思想&#xff1a; 从头到尾依次读取中缀表达式里的每个对象&#xff0c;对不同对象按照不同的情况处理。 如果遇到空格&#xff0c;跳过如果遇到运算数字&#xff0c;直接输出如果遇到左括号&#xff0c;压栈如果遇到右括号&#xff0c;表示括号里的中缀表达式已经扫描完毕&a…

每日一练:LeeCode-654、最大二叉树【二叉树+DFS+分治】

本文是力扣LeeCode-654、最大二叉树【二叉树DFS分治】 学习与理解过程&#xff0c;本文仅做学习之用&#xff0c;对本题感兴趣的小伙伴可以出门左拐LeeCode。 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其…

python安装cv2失败

问题:安装cv2包失败 解决方法&#xff1a; pip install opencv-python或在Anaconda中conda install opencv-python

你好,C++(11)如何用string数据类型表示一串文字?根据初始值自动推断数据类型的auto关键字(C++ 11)

你好&#xff0c;C&#xff08;11&#xff09;如何用string数据类型表示一串文字&#xff1f;根据初始值自动推断数据类型的auto关键字&#xff08;&#xff23; 11&#xff09; 3.5.2 字符串类型 使用char类型的变量我们可以表示单个字符&#xff0c;那么&#xff0c;我们又…

蓝牙BLE学习-蓝牙广播

1.概念 什么叫做广播&#xff0c;顾名思义就像广场上的大喇叭一样&#xff0c;不停的向外传输着信号。不同的是&#xff0c;大喇叭传输的是音频信号&#xff0c;而蓝牙传输的是射频信号。 BLE使用的是无线电波传递信息&#xff0c;就是将数据编码&#xff0c;调制到射频信号中发…

C语言——oj刷题——模拟实现库函数strlen

目录 方法一&#xff1a;迭代法 方法二&#xff1a;递归法 方法三&#xff1a;指针算术法 方法四&#xff1a;汇编指令法 当我们使用C语言进行字符串操作时&#xff0c;经常会用到库函数strlen来获取字符串的长度。strlen函数的作用是计算一个以null字符结尾的字符串的长度…

六、java高级-泛型(一)

六、泛型 1、泛型 从什么是泛型、泛型从何而来、泛型出现是为了解决什么问题、功能及作用说泛型 1.1什么是泛型&#xff1f; 泛型&#xff1a;即“参数化类型”&#xff0c;也就是将需要操作对象的类型进行参数化。在编写代码的时候&#xff0c;不必声明操作对象&#xff08;…

docker从入门到入土

docker到底是什么&#xff1f; docker是世界领先的软件容器平台&#xff0c;基于GO语言进行开发实现docker能够自动执行重复性任务&#xff0c;例如搭建和配置开发环境&#xff0c;从而解放开发人员用户可以方便地创建和使用容器&#xff0c;把自己的应用放入容器&#xff0c;…

基于Robei EDA--实现串口通信

一、串口简介 串口作为常用的三大低速总线&#xff08;UART、SPI、IIC&#xff09;之一&#xff0c;在设计众多通信接口和调试时占有重要地位。但UART和SPI、IIC不同的是&#xff0c;它是异步通信接口&#xff0c;异步通信中的接收方并不知道数据什么时候会到达&#xff0c;所…

int VS Integer

在Java中&#xff0c;int 是一种基本数据类型&#xff08;primitive type&#xff09;&#xff0c;而 Integer 是 int 的包装类&#xff08;wrapper class&#xff09;。它们之间的主要区别在于以下几点&#xff1a; 数据类型&#xff1a;int 是基本的整数类型&#xff0c;它在…