当前位置: 首页 > news >正文

【数据结构】动态规划-基础篇

针对动态规划问题,我总结了以下5步:

确定dp数组以及下标的含义;

递推公式;

dp数组如何初始化;

遍历顺序;

打印dp数组(用来debug);

以上5步适用于任何动态规划问题,下面针对题目,我们来具体实践:

说明:本题代码均为力扣AC代码。

题目一:斐波那契数

class Solution {
public:int fib(int n) {//1.dp[i]表示第i个斐波那契数的值//2.递推公式 dp[i] = dp[i-1] + dp[i-2]//3.dp[0] = 0 dp[1] = 1//4.遍历顺序:本题从前到后遍历即可if(n == 0 || n == 1)return n;vector<int>dp(n+1);dp[0] = 0;dp[1] = 1;for(int i = 2;i <= n;++i){dp[i] = dp[i-1] + dp[i-2];}return dp[n];//返回第n个斐波那契数的值}
};

当然,本题非常简单,不使用动态规划也是OK的。

class Solution {
public:int fib(int n) {//迭代if(n == 0 || n== 1)return n;vector<int>f(n+1);f[0] = 0;f[1] = 1;int cur = 0;for(int i = 2;i <= n;++i){cur = f[0] + f[1];f[0] = f[1];f[1] = cur;}return cur;}
};

 题目二:爬楼梯

分析一波:为啥递推公式是dp[i] = dp[i-1]+dp[i-2]?dp[i]为到达第i阶有dp[i]种方法,.dp[i-1]为到达第i-1阶有dp[i-1]种方法,.dp[i-2]为到达第i-2阶有dp[i-2]种方法,要想到达第i阶,只需从第i-1阶爬一阶或者从第i-2阶爬二阶即可,所以dp[i] = dp[i-1]+dp[i-2]。

class Solution {
public:int climbStairs(int n) {//1.dp[i]为到达第i阶有dp[i]种方法//2.递推公式:dp[i] = dp[i-1]+dp[i-2]//3.dp[1] = 1,dp[2] = 2//遍历顺序:因为dp[i]依赖于dp[i-1]、dp[i-2],所以应该从前到后遍历vector<int> dp(n + 1);if(n == 1 || n == 2)return n;dp[1] = 1;dp[2] = 2;for(int i=3;i<=n;++i){dp[i] = dp[i-1]+dp[i-2];}return dp[n];//爬到第n阶一共有多少种方法}
};

题目三: 使用最小花费爬楼梯

分析一波:本题和上一道爬楼梯很相似,不过是加上了个花费,这里dp[i]为到达i阶楼梯最小的花费,要想到达第i阶,只需从第i-1阶爬一阶或者从第i-2阶爬二阶即可,从第i-1阶爬到第i阶需要花费dp[i-1]+cost[i-1],从第i-2阶爬到第i阶需要花费dp[i-2]+cost[i-2],本题要求最小花费,所以状态转移方程为dp[i] = min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]).

对于初始化,本题说了可以选择从下标为0或1的元素作为初始阶梯,还要注意一点是不跳不花费体力,所以dp[0] = 0,dp[1] = 0.

对于遍历顺序,由于dp[i]是依靠dp[i-1]和dp[i-2]推导的,所以遍历顺序是从前到后。

分析完以后,就能很丝滑的做出来啦!

class Solution {
public:int minCostClimbingStairs(vector<int>& cost) {int n = cost.size();vector<int>dp(n+1);dp[0] = 0;dp[1] = 0;for(int i=2;i<=n;++i){dp[i] = min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);}return dp[n];}
};

题目四:不同路径

分析一波:本题是二维矩阵,所以dp数组应该定义成二维的,dp[i][j]代表从(0,0)位置走到(i,j)位置有多少种不同的路径,可以看到,如果想到达(i,j)的位置,只能从(i,j-1)的位置走一步或者从(i-1,j)的位置向下走一步,所以dp[i][j] = dp[i][j-1]+dp[i-1][j].

对于初始化,要想到达(i,j)的位置,要么从上面过来,要么从左边过来,所以我们要把最左边和最上边都初始化,初始化成多少呢?本题要求只能向右或者向下走,所以最上面行从最左侧走到最右侧只有一种走法,最左侧的列中从最上到最下也只有一种走法,所以初始化如下图。

class Solution {
public:int uniquePaths(int m, int n) {//创建m行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];}
};

题目五:不同路径II

本题和上一题类似,只是本题多了一个障碍物,对于状态转移方程,如果(i,j)位置有障碍的话,那么我们无法继续推导,所以我们需要添加一个条件就是当(i,j)位置不是障碍物时,我们进行推导,否则不去推导。对于初始化,和上一题不同的是,第一列如果有障碍物的话,障碍物后面的位置都无法到达,第一行也是如此,所以我们在初始化时应该加上一个条件,就是当前位置没有障碍物,我们才给dp[i][0]、dp[0][j]初始化成1.

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;//创建m行n列的二维数组vector<vector<int>>dp(m,vector<int>(n));//dp数组初始化for(int i = 0;i < m && obstacleGrid[i][0] == 0;++i)dp[i][0] = 1;for(int j = 0;j < n && obstacleGrid[0][j] == 0;++j)dp[0][j] = 1;for(int i = 1;i < m;++i){for(int j = 1;j < n;j++){if(!obstacleGrid[i][j])dp[i][j] = dp[i-1][j] + dp[i][j-1];}}return dp[m-1][n-1];}
};

题目六:整数拆分

1.确定dp数组含义:dp[i]表示将i进行拆分后得到最大的乘积

2.确定递推公式:将i拆分成两个数最大积为j*(i-j),拆分成三个及以上为j*dp[i-j],这里有个问题,为什么j不拆?实际上,在我们拆分 dp[i-j] 过程中已经包含了拆分 j 的情况,所以这里只考虑如何对 i-j 进行拆分即可,所以递推公式为dp[i] = max(dp[i],max(j*(i-j),j*dp[i-j]))

3.dp数组如何初始化?根据dp数组含义,dp[0] = 0,dp[1] = 0,dp[2] = 1

4.遍历顺序:根据递推公式可以看出,dp[i]的状态依靠dp[i-j]的状态,所以是从前到后遍历。

class Solution {
public:int integerBreak(int n) {if(n == 0 || n == 1)return 0;if(n == 2)return 1;vector<int>dp(n+1);dp[0] = 0,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*(i-j),j*dp[i-j]));}}return dp[n];}
};

对于本题,可以做一个小小的优化。对于拆分i使之乘积最大,一定是拆分成m个近似相同的子数才能得到最大乘积。只不过m我们不知道是几,但是可以确定的是m一定大于等于2,所以在判断条件中,只需要 j <= i/2 即可。举个例子,拆分10的话,可以拆分成5*5,也可以拆分成3*3*4,如果拆分成6*4,后续无论对4如何拆分都不可能得到最大的,因为我们要把i拆分成近似相同的子数才能得到最大值。

题目七:

1.明确dp数组及下标含义:1到i为节点的二叉搜索树的个数为dp[i]

2.递推公式:根据图中分析,dp[3]就是以元素1为头结点BST的数量+以元素2为头结点BST的数量+以元素3为头结点BST的数量,我们要计算dp[i],只需要让 j 从遍历 1 到 i,计算 j 为头结点对应BST的个数并将他们相加即可。注意,j为头结点时,其左子树数目为 j-1 个,右子树数目为 i-j 个状态转移方程:dp[i] += dp[j-1]*dp[i-j].

3.如何初始化?dp[0] = 1,因为空BST也是BST

4.遍历顺序:从前到后

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

相关文章:

【数据结构】动态规划-基础篇

针对动态规划问题&#xff0c;我总结了以下5步&#xff1a; 确定dp数组以及下标的含义&#xff1b; 递推公式&#xff1b; dp数组如何初始化&#xff1b; 遍历顺序&#xff1b; 打印dp数组&#xff08;用来debug&#xff09;&#xff1b; 以上5步适用于任何动态规划问题&#x…...

opencv读取展示图片

import time import cv2 # 创建窗口 cv2.namedWindow(window, cv2.WINDOW_AUTOSIZE) # cv2.WINDOW_AUTOSIZE自动大小&#xff0c;不允许修改窗口大小 cat cv2.imread("./6.jpg", 0) # opencv默认读取bgr,0代表的是灰度图模式,1是彩色图 # 展示名字为window…...

网站访问统计A/B测试与数据分析

在网站运营中&#xff0c;访问统计和数据分析是优化用户体验和提高转化率的关键工具。A/B测试作为一种数据驱动的方法&#xff0c;能够帮助网站运营者验证设计和内容的有效性。A/B测试的基本原理是同时展示两个不同的版本&#xff08;A和B&#xff09;&#xff0c;通过比较它们…...

前端开发 之 15个页面加载特效下【附完整源码】

文章目录 十二&#xff1a;铜钱3D圆环加载特效1.效果展示2.HTML完整代码 十三&#xff1a;扇形百分比加载特效1.效果展示2.HTML完整代码 十四&#xff1a;四色圆环显现加载特效1.效果展示2.HTML完整代码 十五&#xff1a;跷跷板加载特效1.效果展示2.HTML完整代码 十二&#xff…...

详解八大排序(六)------(三路划分,自省排序,归并排序外排序)

文章目录 1. 快排之三路划分1. 1 三路划分的诞生由来1. 2 三路划分的具体思路1. 3 代码实现 2. 快排之自省排序2. 1 自省排序的目的2. 2 自省排序的思路2. 3 自省排序的实现代码 3. 归并排序外排序3. 1 外排序介绍3. 2 归并排序外排序的思路3. 3 归并排序的实现代码 1. 快排之三…...

【Java从入门到放弃 之 从字节码的角度异常处理】

从字节码的角度异常处理 生成字节码Javap 命令的使用基本语法 字节码文件testTryCatchtestTryCatchFinallytestTryWithResource 如果大家对与java的异常使用还有问题或者还不太了解&#xff0c;建议先看一下我之前写的Java异常了解一下基本 的异常处理知识&#xff0c;再看这篇…...

Java虚拟机(JVM)中的元空间(Metaspace)一些关键点的总结

• 元空间的引入&#xff1a;在Java 8中&#xff0c;JVM的内存结构经历了变化&#xff0c;其中方法区被替代为元空间&#xff08;Metaspace&#xff09;。元空间用于存储类的元数据信息&#xff0c;包括类的名称、方法、字段等信息。 • 存储位置&#xff1a;与方法区不同&…...

小程序 模版与配置

WXML模版语法 一、数据绑定 1、数据绑定的基本原则 &#xff08;1&#xff09;在data中定义数据 &#xff08;2&#xff09;在WXML中使用数据 2、在data中定义页面的数据 3、Mustache语法的格式&#xff08;双大括号&#xff09; 4、Mustache语法的应用场景 &#xff08;…...

当大的div中有六个小的div,上面三个下面三个,当外层div高变大的时候我希望里面的小的div的高也变大

问&#xff1a; 当大的div中有六个小的div&#xff0c;上面三个下面三个&#xff0c;当外层div高变大的时候我希望里面的小的div的高也变大 回答&#xff1a; 这时候我们就不能写死六个小的div的高度&#xff0c;否则上下的小的div的间距就会变大&#xff0c;因为他们的高度…...

MySQL——操作

一.库的操作 1.基本操作 创建数据库 create database 数据库名称; 查看数据库 show databases; 删除数据库 drop database 数据库名称; 执行删除之后的结果: 数据库内部看不到对应的数据库 对应的数据库文件夹被删除&#xff0c;级联删除&#xff0c;里面的数据表全部被删…...

Python语法之正则表达式详解以及re模块中的常用函数

正则表达式详解及re模块中的常用函数 概念、作用和步骤 概念&#xff1a; 本身也是一个字符串&#xff0c;其中的字符具有特殊含义&#xff0c;将来我们可以根据这个字符串【正则表达式】去处理其他的字符串&#xff0c;比如可以对其他字符串进行匹配&#xff0c;切分&#xf…...

《地球化学》

《地球化学》主要报道近代地球化学, 特别是其主要分支学科, 如岩石地球化学、元素地球化学、有机地球化学、环境地球化学、矿床地球化学、实验地球化学、生物地球化学、天体化学、计算地球化学、分析地球化学、海洋地球化学、沉积地球化学、纳米地球化学、油气地球化学和同位素…...

alpine openssl 编译

./config no-shared --prefix/usr/local/openssl apk add musl-dev gcc g apk add linux-headers ssh root 登录 编辑 SSH 配置文件 打开 SSH 配置文件 /etc/ssh/sshd_config&#xff1a; vi /etc/ssh/sshd_config PermitRootLogin yes...

【AI模型对比】AI新宠Kimi与ChatGPT的全面对比:技术、性能、应用全揭秘

文章目录 Moss前沿AI技术背景Kimi人工智能的技术积淀ChatGPT的技术优势 详细对比列表模型研发Kimi大模型的研发历程ChatGPT的发展演进 参数规模与架构Kimi大模型的参数规模解析ChatGPT的参数体系 模型表现与局限性Kimi大模型的表现ChatGPT的表现 结论&#xff1a;如何选择适合自…...

【C#设计模式(17)——迭代器模式(Iterator Pattern)】

前言 迭代器模式可以使用统一的接口来遍历不同类型的集合对象&#xff0c;而不需要关心其内部的具体实现。 代码 //迭代器接口 public interface Iterator {bool HashNext();object Next(); } //集合接口 public interface Collection {Iterator CreateIterator(); } //元素迭…...

二、部署docker

二、安装与部署 2.1 安装环境概述 Docker划分为CE和EE&#xff0c;CE为社区版&#xff08;免费&#xff0c;支持周期三个月&#xff09;&#xff0c;EE为企业版&#xff08;强调安全&#xff0c;付费使用&#xff09;。 Docker CE每月发布一个Edge版本&#xff08;17.03&…...

FFmpeg 4.3 音视频-多路H265监控录放C++开发十九,ffmpeg封装

封装就是将 一个h264&#xff0c;和一个aac文件重新封装成一个mp4文件。 这里我们的h264 和 aac都是来源于另一个mp4文件&#xff0c;也就是说&#xff0c;我们会将 in.mp4文件解封装成一路videoavstream 和 一路 audioavstream&#xff0c;然后 将这两路的 avstream 合并成一…...

ML 系列:第 39 节 - 估计方法:最大似然估计 (MLE)

目录 一、说明 二、什么是最大似然估计 (MLE)&#xff1f; 2.1 理解公式 2.2 MLE 的定义 2.3 我们何时使用 MLE&#xff1f; 三、结论 一、说明 在统计学领域&#xff0c;我们经常需要根据观察到的数据估计统计模型的参数。为此目的广泛使用的两种关键方法是最大似然估计 ( MLE…...

Linux 权限管理:用户分类、权限解读与常见问题剖析

&#x1f31f; 快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。&#x1f31f; &#x1f6a9;用通俗易懂且不失专业性的文字&#xff0c;讲解计算机领域那些看似枯燥的知识点&#x1f6a9; 目录 &#x1f4af;L…...

网络原理之 UDP 协议

目录 1. UDP 协议报文格式 2. UDP 的特点 (1) 无连接 (2) 不可靠 (3) 面向数据报 (4) 全双工 3. 基于 UDP 的应用层协议 前文是&#xff1a;UDP 的使用 首先了解一下基础知识&#xff1a; 1. UDP 协议报文格式 传输层最重要的协议有两个&#xff0c;一个是 TCP&#x…...

并发框架disruptor实现生产-消费者模式

Disruptor是LMAX公司开源的高性能内存消息队列&#xff0c;单线程处理能力可达600w订单/秒。本文将使用该框架实现生产-消费者模式。一、框架的maven依赖 <!-- https://mvnrepository.com/artifact/com.lmax/disruptor --><dependency><groupId>com.lmax<…...

【Vivado】xdc约束文件编写

随手记录一下项目中学到的约束文件编写技巧。 时序约束 创建生成时钟 参考链接&#xff1a; Vivado Design Suite Tcl Command Reference Guide (UG835) Vivado Design Suite User Guide: Using Constraints (UG903) 通过Clocking Wizard IP创建的时钟&#xff08;MMCM或…...

Redis使用场景-缓存-缓存雪崩

前言 之前在针对实习面试的博文中讲到Redis在实际开发中的生产问题&#xff0c;其中缓存穿透、击穿、雪崩在面试中问的最频繁&#xff0c;本文加了图解&#xff0c;希望帮助你更直观的了解缓存雪崩&#x1f600; &#xff08;放出之前写的针对实习面试的关于Redis生产问题的博…...

概率论相关知识随记

作为基础知识的补充&#xff0c;随学随记&#xff0c;方便以后查阅。 概率论相关知识随记 期望&#xff08;Expectation&#xff09;期望的定义离散型随机变量的期望示例&#xff1a;掷骰子的期望 连续型随机变量的期望示例&#xff1a;均匀分布的期望 期望的性质线性性质期望的…...

【PlantUML系列】序列图(二)

目录 一、参与者 二、消息交互顺序 三、其他技巧 3.1 改变参与者的顺序 3.2 使用 as 重命名参与者 3.3 注释 3.4 页眉和页脚 一、参与者 使用 participant、actor、boundary、control、entity 和 database 等关键字来定义不同类型的参与者。例如&#xff1a; Actor&…...

WPF+MVVM案例实战与特效(三十四)- 日志管理:使用 log4net 实现高效日志记录

文章目录 1、概述2、日志案例实现1、LogHelper 类详解2、代码解释3、配置文件4、实际应用案例场景 1:记录系统运行日志场景 2:记录数据库操作日志场景 3:记录 HTTP 请求日志5、总结1、概述 在WPF软件开发中,良好的日志记录机制对于系统的调试、维护和性能优化至关重要。lo…...

前端测试框架 jasmine 的使用

最近的项目在使用AngulaJs,对JS代码的测试问题就摆在了面前。通过对比我们选择了 Karma jasmine ,使用 Jasmine做单元测试 &#xff0c;Karma 自动化完成&#xff0c;当然了如果使用 Karma jasmine 前提是必须安装 Nodejs。 安装好 Nodejs &#xff0c;使用 npm 安装好必要…...

Qwen2-VL视觉大模型微调实战:LaTex公式OCR识别任务(完整代码)

《SwanLab机器学习实战教程》是一个主打「开箱即用」的AI训练系列教程&#xff0c;我们致力于提供完善的数据集、源代码、实验记录以及环境安装方式&#xff0c;手把手帮助你跑起训练&#xff0c;解决问题。 Qwen2-VL是通义千问团队最近开源的大语言模型&#xff0c;由阿里云通…...

「Mac玩转仓颉内测版42」小学奥数篇5 - 圆和矩形的面积计算

本篇将通过 Python 和 Cangjie 双语解决简单的几何问题&#xff1a;计算圆的面积和矩形的面积。通过这道题&#xff0c;学生将掌握如何使用公式解决几何问题&#xff0c;并学会用编程实现数学公式。 关键词 小学奥数Python Cangjie几何计算 一、题目描述 编写一个程序&#…...

Groom Blender to UE5

Groom Blender to UE5 - Character & Animation - Epic Developer Community Forums Hello, 你好&#xff0c; While exporting my “groom” from blender to UE5, I notice that the curves have a minimal resolution in Unreal. However I would like to get the same …...