【代码随想录day33】【C++复健】62.不同路径;63. 不同路径 II;343. 整数拆分;96.不同的二叉搜索树

感觉dp的题真的很适合背,当然不是死记硬背,而是当做一种模板题,出来一道新的题就往模板题上面去靠,如果套对模板的话剩下的事情其实就简单了。所以只要看一遍解法知道大致思路其实就够了,毕竟大部分dp的代码也不算难写。

62.不同路径

先是使用二维dp数组的方法,结果发现二维数组的定义有点忘了,于是乱写了一个,没想到对了,就是vector<vector<int>> dp(m, vector<int>(n));

其他部分的话就没有太多好说的。

class Solution {
public:int uniquePaths(int m, int n) {vector<vector<int>> dp(m, vector<int>(n));for(int i=0; i<m; i++){dp[i][0] = 1;}for(int j=0; j<n; j++){dp[0][j] = 1;}for(int i=1; i<m; i++){for(int j=1; j<n; j++){dp[i][j] = dp[i][j-1] + dp[i-1][j];}}return dp[m-1][n-1];}
};

然后重点说下这个一维的解法:
第一遍写的时候把i和j的顺序写反了,结果就是完全不对了。一开始觉得不就是遍历顺序从横着变成竖着嘛,有什么不一样的?

思考良久,发现是在定义这个dp数组的时候,我们把长度定义成了dp[n],而实际上每次循环经过的是m次,简单来说就是会把值存错位置,导致无法得到正确结果。

可以对比一下下面这两段代码:

class Solution {
public:int uniquePaths(int m, int n) {vector<int> dp(n);for(int i=0; i<n; i++){dp[i] = 1;}for(int j=1; j<m; j++){for(int i=1; i<n; i++){dp[i] = dp[i] + dp[i-1];}cout << endl;}return dp[n-1];}
};
class Solution {
public:int uniquePaths(int m, int n) {vector<int> dp(m);for(int i=0; i<m; i++){dp[i] = 1;}for(int j=1; j<n; j++){for(int i=1; i<m; i++){dp[i] = dp[i] + dp[i-1];}cout << endl;}return dp[m-1];}
};

这两段代码都是可以正确提交的,区别在于,当我们想要变更循环顺序的时候,需要把dp数组的定义和初始化也都相应的变一下,不然就会发生报错。

总结一下,就是dp数组长度要与内层循环相等,写出来之后我自己都吓了一跳,这么简单的道理我怎么就没想到呢。当我们要动态更新一个长度为n的数组的时候,当然是每次循环都把这n个数都更新一遍,然后重复m次才对嘛。

63. 不同路径 II

有了上一题的结论做基础,本题即使是一维数组,也必将一遍拿下... 吗?

写了一套看似没什么问题的代码,实际上却没法全过:

class Solution {
public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {int m = obstacleGrid.size();int n = obstacleGrid[0].size();if(obstacleGrid[0][0]==1 || obstacleGrid[m-1][n-1]==1){return 0;}vector<int> dp(n);dp[0] = 1;for(int i=0; i<n; i++){if(obstacleGrid[0][i] == 1){break;}dp[i] = 1;}for(int j=1; j<m; j++){for(int i=1; i<n; i++){if(obstacleGrid[j][i] == 1){dp[i] = 0;}else{dp[i] = dp[i] + dp[i-1];}}}return dp[n-1];}
};

问题出在哪里了?我们在循环的时候,如果按上一题一样,实际上是默认每次循环的dp[0]都是等于1的,但是本题当中却不能做这样的假设,因为如果在某次循环的0号位有一个障碍物,从此时开始的dp[0]应该是0才对,而并不是1。这个时候我们就不能像上一题一样从i=1开始了,而是要从i=0开始,但是此时又出现了问题,i=0的是时候,dp[i-1]又变成非法访问了,所以要再加一个i>0的判断,最终的代码如下:

class Solution {
public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {int m = obstacleGrid.size();int n = obstacleGrid[0].size();if(obstacleGrid[0][0]==1 || obstacleGrid[m-1][n-1]==1){return 0;}vector<int> dp(n);dp[0] = 1;for(int i=0; i<n; i++){if(obstacleGrid[0][i] == 1){break;}dp[i] = 1;}for(int j=1; j<m; j++){for(int i=0; i<n; i++){if(obstacleGrid[j][i] == 1){dp[i] = 0;}else if(i>0){dp[i] = dp[i] + dp[i-1];}}}return dp[n-1];}
};

 验证一下上题的结论,用m也能通过:

class Solution {
public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {int m = obstacleGrid.size();int n = obstacleGrid[0].size();if(obstacleGrid[0][0]==1 || obstacleGrid[m-1][n-1]==1){return 0;}vector<int> dp(m);dp[0] = 1;for(int j=0; j<m; j++){if(obstacleGrid[j][0] == 1){break;}dp[j] = 1;}for(int i=1; i<n; i++){for(int j=0; j<m; j++){if(obstacleGrid[j][i] == 1){dp[j] = 0;}else if(j>0){dp[j] = dp[j] + dp[j-1];}}}return dp[m-1];}
};

最后就是,其实买你对这种比较难的题,其实没必要非得用一维dp数组的思路去想,思路上面会相对复杂。

343. 整数拆分

一周目其实已经做过这题,二周目试图复现思路,但漏了情况。

1 外层的max的含义:

dp[i]代表之前算出的乘积中最大的那个,后面的那个代表本次的新结果的乘积,两个比较之后取一个最大值,代表动态更新的最大乘积。

2 内层的max的含义:

j*dp[i-j]代表分j出来,并且拿剩下的继续拆分。因为dp[i-j]代表的是将i-j至少拆成2个值之后的最大乘积,保留i-j原本的值不进行拆分的情况并不在此列。因此我们此处还需要一个额外的max。

class Solution {
public:int integerBreak(int n) {vector<int> dp(n+1);dp[1] = 0;dp[2] = 1;for(int i=3; i<=n; i++){for(int j=1; j<i; j++){dp[i] = max(dp[i], max(j*dp[i-j], j*(i-j)));}}return dp[n];}
};

本题我就是漏了里面的max,以为只要写j*dp[i-j]即可,就错了。

还有就是我这么定义n+1的dp数组,一定要注意终止条件要设置成i <= n,否则就会出现dp[n]是0的情况(害我想半天)。

96.不同的二叉搜索树

本题其实是相当有难度的,一周目记得做到的时候毫无思路,但也因此这个题给我留下了深刻的印象,清楚地知道就是从i处对数组截断,两边取dp数组得到的值最后算个乘积,所以一遍就做出来了。

class Solution {
public:int numTrees(int n) {vector<int> dp(n+1);dp[0] = 1;dp[1] = 1;for(int i=2; i<=n; i++){for(int j=1; j<=i; j++){dp[i] += dp[j-1]*dp[i-j];}}return dp[n];}
};

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

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

相关文章

SHELL笔记(条件测试)

基本概念&#xff1a; 条件测试用于在 Shell 脚本中对各种条件进行判断&#xff0c;根据判断结果来决定是否执行特定的命令或代码块。条件测试可以用于比较数值、字符串&#xff0c;检查文件或目录的属性&#xff0c;以及判断命令的执行结果等。 格式&#xff1a; 格式1&…

JDK、MAVEN与IDEA的安装与配置

1.认识JDK、MAVEN与IDEA JDK 提供了编译和运行Java程序的基本环境。Maven 帮助管理项目的构建和依赖。IDEA 提供了一个强大的开发环境&#xff0c;使得编写、调试和运行Java程序更加高效。 2. 安装与环境配置 2.1 官网地址 选择你需要的版本下载&#xff1a; MAVEN下载传送…

微信小程序-prettier 格式化

一.安装prettier插件 二.配置开发者工具的设置 配置如下代码在setting.json里&#xff1a; "editor.formatOnSave": true,"editor.defaultFormatter": "esbenp.prettier-vscode","prettier.documentSelectors": ["**/*.wxml"…

【Mac】未能完成该操作 Unable to locate a Java Runtime

重生之我做完产品经理之后回来学习Data Mining Mac打开weka.jar报错"未能完成该操作 Unable to locate a Java Runtime" 1. 打开终端执行 java -version 指令&#xff0c;原来是没安装 JDK 环境 yyzccnn-mac ~ % java -version The operation couldn’t be comple…

【ArcGIS微课1000例】0127:计算城市之间的距离

本文讲述,在ArcGIS中,计算城市(以地级城市为例)之间的距离,效果如下图所示: 一、数据准备 加载配套实验数据包中的地级市和行政区划矢量数据(订阅专栏后,从私信查收数据),如下图所示: 二、计算距离 1. 计算邻近表 ArcGIS提供了计算点和另外点之间距离的工具:分析…

【WPF】Prism学习(五)

Prism Commands 1.错误处理&#xff08;Error Handling&#xff09; Prism 9 为所有的命令&#xff08;包含AsyncDelegateCommand&#xff09;提供了更好的错误处理。 避免用try/catch包装每一个方法根据不同遇到的异常类型来提供特定的逻辑处理可以在多个命令之间共享错误处…

【element-tiptap】Tiptap编辑器核心概念----结构篇

core-concepts 前言&#xff1a;这篇文章来介绍一下 Tiptap 编辑器的一些核心概念 &#xff08;一&#xff09;结构 1、 Schemas 定义文档组成方式。一个文档就是标题、段落以及其他的节点组成的一棵树。 每一个 ProseMirror 的文档都有一个与之相关联的 schema&#xff0c;…

2024.6使用 UMLS 集成的基于 CNN 的文本索引增强医学图像检索

Enhancing Medical Image Retrieval with UMLS-Integrated CNN-Based Text Indexing 问题 医疗图像检索中&#xff0c;图像与相关文本的一致性问题&#xff0c;如患者有病症但影像可能无明显异常&#xff0c;影响图像检索系统准确性。传统的基于文本的医学图像检索&#xff0…

PGMP-练DAY26

1. Which of the following items are key elements of the program charter?以下哪些项目是项目集章程的关键要素&#xff1f; A.Scope, assumptions,constraints,goals and objectives, timing, key stakeholders.范围、假设、约束、目标和目的、时间安排、主要利益相关者 …

Spark_写ORALCE:ORA-01426 numeric overflow 问题解决

问题 是这样的&#xff0c;20241118&#xff0c;我spark程序写Oracle时候&#xff0c;关联完HBase数据后&#xff0c;在写入ORACLE中&#xff0c;遇到了这个bug&#xff0c; 数据入到一半&#xff0c;每次都报错ORA-01426 numeric overflow&#xff0c;具体呢&#xff0c;也不告…

初识Linux · 信号处理 · 续

目录 前言&#xff1a; 可重入函数 重谈进程等待和优化 前言&#xff1a; 在前文&#xff0c;我们已经介绍了信号产生&#xff0c;信号保存&#xff0c;信号处理的主题内容&#xff0c;本文作为信号处理的续篇&#xff0c;主要是介绍一些不那么重要的内容&#xff0c;第一个…

流量模型 -20241118

流量模型 个体的注意力注意力提升销量&#xff0c;转化为直接收益&#xff0c;同时提升品牌价值购物平台的出现使注意力变现变得简单&#xff0c;开拓了注意力的的使用方式&#xff0c;使其分散使用转变为集中使用各个视频&#xff0c;直播平台集中注意力&#xff0c;使得流量…

微信小程序 最新获取用户头像以及用户名

一.在小程序改版为了安全起见 使用用户填写来获取头像以及用户名 二.代码实现 <view class"login_box"><!-- 头像 --><view class"avator_box"><button wx:if"{{ !userInfo.avatarUrl }}" class"avatorbtn" op…

WPF MVVM框架

一、MVVM简介 MVC Model View Control MVP MVVM即Model-View-ViewModel&#xff0c;MVVM模式与MVP&#xff08;Model-View-Presenter&#xff09;模式相似&#xff0c;主要目的是分离视图&#xff08;View&#xff09;和模型&#xff08;Model&#xff09;&#xff0c;具有低…

云原生周刊:Kubernetes v1.32 要来了

开源项目推荐 Woodpecker Woodpecker 是一款轻量级且功能强大的 CI/CD 引擎&#xff0c;以其高度可扩展性和易用性著称。它支持多种版本控制系统与编程语言&#xff0c;能够灵活适配不同开发流程&#xff0c;帮助团队实现高效的持续集成与交付。无论是个人项目还是大型团队&a…

Elasticsearch-Elasticsearch-Rest-Client(三)

1&#xff09;TCP spring-data-elasticsearch:transport-api.jar&#xff1b; springboot版本不同&#xff0c;transport-api.jar不同&#xff0c;不能适配es版本, 7.x已经不建议使用&#xff0c;8以后就要废弃 2&#xff09;、9200&#xff1a;HTTP JestClient&#xff1a;…

【算法】【优选算法】前缀和(下)

目录 一、560.和为K的⼦数组1.1 前缀和1.2 暴力枚举 二、974.和可被K整除的⼦数组2.1 前缀和2.2 暴力枚举 三、525.连续数组3.1 前缀和3.2 暴力枚举 四、1314.矩阵区域和4.1 前缀和4.2 暴力枚举 一、560.和为K的⼦数组 题目链接&#xff1a;560.和为K的⼦数组 题目描述&#x…

区块链预言机;预言机的部署、与智能合约的关系以及是否分布式;基于Fabric联盟链与链外世界的数据交互

目录 区块链预言机 简单理解 举例说明 注意事项 预言机的部署、与智能合约的关系以及是否分布式 预言机的部署 预言机与智能合约的关系 预言机是否分布式 简单举例说明 基于Fabric联盟链与链外世界的数据交互 预言机整体架构 推送预言机 区块链预言机 是一个相对专…

两大新兴开发语言大比拼:Move PK Rust

了解 Move 和 Rust 的差异有助于开发者根据项目的具体需求选择最合适的语言。选择不恰当的语言可能会导致项目后期出现技术债务。不同语言有其独特的优势。了解 Move 和 Rust 的差异可以帮助开发者拓展技术视野&#xff0c;发现不同语言在不同领域的应用潜力。 咱们直奔主题&a…

Scaling Law的“终结“还是新起点?——开源实践者的深度思考

作者&#xff1a;宋大宝&#xff0c;与大宝同学因那篇《回顾总结展望「融合RL与LLM思想&#xff0c;探寻世界模型以迈向AGI」》结识于今年春天&#xff0c;虽我们当时某些思想观念有些出入&#xff0c;也碰撞出了很多火花与共鸣&#xff0c;并持续地相互启发的走到了现在。他是…