代码随想录算法训练营第32天 动态规划part01| 题目:理论基础 、 509. 斐波那契数 、70. 爬楼梯 、 746. 使用最小花费爬楼梯

news2024/9/22 7:23:17

代码随想录算法训练营第32天 动态规划part01| 题目:理论基础 、 509. 斐波那契数 、70. 爬楼梯 、 746. 使用最小花费爬楼梯

文章来源:代码随想录
理论

题目名称:509. 斐波那契数

斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) = 0,F(1) = 1 F(n) = F(n - 1) + F(n - 2),其中 n > 1 给你n ,请计算 F(n) 。

示例 1:

输入:2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1
示例 2:

输入:3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2
示例 3:

输入:4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3
提示:

0 <= n <= 30

第一想法:

简单的模拟就可以解决,重要是要体现dp的步骤

解答思路:

斐波那契数列大家应该非常熟悉不过了,非常适合作为动规第一道题目来练练手。

因为这道题目比较简单,可能一些同学并不需要做什么分析,直接顺手一写就过了。

但「代码随想录」的风格是:简单题目是用来加深对解题方法论的理解的。

通过这道题目让大家可以初步认识到,按照动规五部曲是如何解题的。

对于动规,如果没有方法论的话,可能简单题目可以顺手一写就过,难一点就不知道如何下手了。

所以我总结的动规五部曲,是要用来贯穿整个动态规划系列的,就像之前讲过二叉树系列的递归三部曲 (opens new window),回溯法系列的回溯三部曲 (opens new window)一样。后面慢慢大家就会体会到,动规五部曲方法的重要性。

#动态规划
动规五部曲:

这里我们要用一个一维dp数组来保存递归的结果

1.确定dp数组以及下标的含义
dp[i]的定义为:第i个数的斐波那契数值是dp[i]

2.确定递推公式
为什么这是一道非常简单的入门题目呢?

因为题目已经把递推公式直接给我们了:状态转移方程 dp[i] = dp[i - 1] + dp[i - 2];

3.dp数组如何初始化
题目中把如何初始化也直接给我们了,如下:

dp[0] = 0;
dp[1] = 1;
4.确定遍历顺序
从递归公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,dp[i]是依赖 dp[i - 1] 和 dp[i - 2],那么遍历的顺序一定是从前到后遍历的

5.举例推导dp数组
按照这个递推公式dp[i] = dp[i - 1] + dp[i - 2],我们来推导一下,当N为10的时候,dp数组应该是如下的数列:

0 1 1 2 3 5 8 13 21 34 55

如果代码写出来,发现结果不对,就把dp数组打印出来看看和我们推导的数列是不是一致的。

时间复杂度:O(n)
空间复杂度:O(n)
当然可以发现,我们只需要维护两个数值就可以了,不需要记录整个序列。

收获:

题目名称:70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1 阶 + 1 阶
2 阶
示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1 阶 + 1 阶 + 1 阶
1 阶 + 2 阶
2 阶 + 1 阶

第一想法:

首先1. dp[i]是第i个楼梯到达的方法数

解答思路:

本题大家如果没有接触过的话,会感觉比较难,多举几个例子,就可以发现其规律。

爬到第一层楼梯有一种方法,爬到二层楼梯有两种方法。

那么第一层楼梯再跨两步就到第三层 ,第二层楼梯再跨一步就到第三层。

所以到第三层楼梯的状态可以由第二层楼梯 和 到第一层楼梯状态推导出来,那么就可以想到动态规划了。

我们来分析一下,动规五部曲:

定义一个一维数组来记录不同楼层的状态

1.确定dp数组以及下标的含义
dp[i]: 爬到第i层楼梯,有dp[i]种方法

2.确定递推公式
如何可以推出dp[i]呢?

从dp[i]的定义可以看出,dp[i] 可以有两个方向推出来。

首先是dp[i - 1],上i-1层楼梯,有dp[i - 1]种方法,那么再一步跳一个台阶不就是dp[i]了么。

还有就是dp[i - 2],上i-2层楼梯,有dp[i - 2]种方法,那么再一步跳两个台阶不就是dp[i]了么。

那么dp[i]就是 dp[i - 1]与dp[i - 2]之和!

所以dp[i] = dp[i - 1] + dp[i - 2] 。

在推导dp[i]的时候,一定要时刻想着dp[i]的定义,否则容易跑偏。

这体现出确定dp数组以及下标的含义的重要性!

3.dp数组如何初始化
再回顾一下dp[i]的定义:爬到第i层楼梯,有dp[i]种方法。

那么i为0,dp[i]应该是多少呢,这个可以有很多解释,但基本都是直接奔着答案去解释的。

例如强行安慰自己爬到第0层,也有一种方法,什么都不做也就是一种方法即:dp[0] = 1,相当于直接站在楼顶。

但总有点牵强的成分。

那还这么理解呢:我就认为跑到第0层,方法就是0啊,一步只能走一个台阶或者两个台阶,然而楼层是0,直接站楼顶上了,就是不用方法,dp[0]就应该是0.

其实这么争论下去没有意义,大部分解释说dp[0]应该为1的理由其实是因为dp[0]=1的话在递推的过程中i从2开始遍历本题就能过,然后就往结果上靠去解释dp[0] = 1。

从dp数组定义的角度上来说,dp[0] = 0 也能说得通。

需要注意的是:题目中说了n是一个正整数,题目根本就没说n有为0的情况。

所以本题其实就不应该讨论dp[0]的初始化!

我相信dp[1] = 1,dp[2] = 2,这个初始化大家应该都没有争议的。

所以我的原则是:不考虑dp[0]如何初始化,只初始化dp[1] = 1,dp[2] = 2,然后从i = 3开始递推,这样才符合dp[i]的定义。

4.确定遍历顺序
从递推公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,遍历顺序一定是从前向后遍历的

5.举例推导dp数组
举例当n为5的时候,dp table(dp数组)应该是这样的
在这里插入图片描述

困难:

抽象出动态公式,使用五步法去考虑。

题目名称:746. 使用最小花费爬楼梯

旧题目描述:

数组的每个下标作为一个阶梯,第 i 个阶梯对应着一个非负数的体力花费值 cost[i](下标从 0 开始)。

每当你爬上一个阶梯你都要花费对应的体力值,一旦支付了相应的体力值,你就可以选择向上爬一个阶梯或者爬两个阶梯。

请你找出达到楼层顶部的最低花费。在开始时,你可以选择从下标为 0 或 1 的元素作为初始阶梯。

示例 1:

输入:cost = [10, 15, 20]
输出:15
解释:最低花费是从 cost[1] 开始,然后走两步即可到阶梯顶,一共花费 15 。
示例 2:

输入:cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
输出:6
解释:最低花费方式是从 cost[0] 开始,逐个经过那些 1 ,跳过 cost[3] ,一共花费 6 。
提示:

cost 的长度范围是 [2, 1000]。
cost[i] 将会是一个整型数据,范围为 [0, 999] 。

第一想法:

1.dp[i]是到达第i个阶梯的最少cost
2.dp[i]=dp[i-1]+cost[i-1]或者dp[i]=dp[i-2]+cost[i-2],选择最小的即可

解答思路:

修改之后的题意就比较明确了,题目中说 “你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯” 也就是相当于 跳到 下标 0 或者 下标 1 是不花费体力的, 从 下标 0 下标1 开始跳就要花费体力了。

1.确定dp数组以及下标的含义
使用动态规划,就要有一个数组来记录状态,本题只需要一个一维数组dp[i]就可以了。

dp[i]的定义:到达第i台阶所花费的最少体力为dp[i]。

对于dp数组的定义,大家一定要清晰!

2.确定递推公式
可以有两个途径得到dp[i],一个是dp[i-1] 一个是dp[i-2]。

dp[i - 1] 跳到 dp[i] 需要花费 dp[i - 1] + cost[i - 1]。

dp[i - 2] 跳到 dp[i] 需要花费 dp[i - 2] + cost[i - 2]。

那么究竟是选从dp[i - 1]跳还是从dp[i - 2]跳呢?

一定是选最小的,所以dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);

3.dp数组如何初始化
看一下递归公式,dp[i]由dp[i - 1],dp[i - 2]推出,既然初始化所有的dp[i]是不可能的,那么只初始化dp[0]和dp[1]就够了,其他的最终都是dp[0]dp[1]推出。

那么 dp[0] 应该是多少呢? 根据dp数组的定义,到达第0台阶所花费的最小体力为dp[0],那么有同学可能想,那dp[0] 应该是 cost[0],例如 cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] 的话,dp[0] 就是 cost[0] 应该是1。

这里就要说明本题力扣为什么改题意,而且修改题意之后 就清晰很多的原因了。

新题目描述中明确说了 “你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。” 也就是说 到达 第 0 个台阶是不花费的,但从 第0 个台阶 往上跳的话,需要花费 cost[0]。

所以初始化 dp[0] = 0,dp[1] = 0;

4.确定遍历顺序
最后一步,递归公式有了,初始化有了,如何遍历呢?

本题的遍历顺序其实比较简单,简单到很多同学都忽略了思考这一步直接就把代码写出来了。

因为是模拟台阶,而且dp[i]由dp[i-1]dp[i-2]推出,所以是从前到后遍历cost数组就可以了。

但是稍稍有点难度的动态规划,其遍历顺序并不容易确定下来。 例如:01背包,都知道两个for循环,一个for遍历物品嵌套一个for遍历背包容量,那么为什么不是一个for遍历背包容量嵌套一个for遍历物品呢? 以及在使用一维dp数组的时候遍历背包容量为什么要倒序呢?

这些都与遍历顺序息息相关。当然背包问题后续「代码随想录」都会重点讲解的!

5.举例推导dp数组
拿示例2:cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] ,来模拟一下dp数组的状态变化
在这里插入图片描述

class Solution {
    public int minCostClimbingStairs(int[] cost) {
       int[] dp= new int[cost.length+1];
       dp[0]=0;
       dp[1]=0;
       for(int i=2;i<=cost.length;i++){
        dp[i]=Math.min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
       }
       return dp[cost.length];
    }
}

收获:

注意dp[i]的边界定义问题,是否第一步不花费,cost大小与楼层的规定,dp[0]所代表的意义。

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

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

相关文章

【论文分享】GPU Memory Exploitation for Fun and Profit 24‘USENIX

目录 AbstractIntroductionResponsible disclosure BackgroundGPU BasicsGPU architectureGPU virtual memory management GPU Programming and ExecutionGPU programming modelGPU kernelDevice function NVIDIA PTX and SASSSASS instruction encoding GPU Memory SpacesGlob…

react购物车Redux

入口index.js import React from react import {createRoot} from react-dom/clientimport App from ./App //注入store import {Provider} from "react-redux"; import store from "./store";const root createRoot(document.getElementById(root)) roo…

Python系统教程003

变量的数据类型 将输入信息存入变量name中然后输出。 如果想通过键盘输 入信息再存入变量 中应该怎么办&#xff1f; 一、内容 input函数变量的数据类型变量的运算 &#xff08;一&#xff09;、input函数 1、input函数1 函数&#xff1a;用来完成某一个特定功能的代码 …

2.第二阶段x86游戏实战2-认识进制、理解数据宽度和位的概念

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

NXP,S32K1XX汽车通用微控制器开发笔记

文章目录 1. 概述2. 开发环境配置2.1 S32 Design Studio2.2 安装SDK2.3 新建demo工程2.4 字体配置2.5 按需求修改demo2.5.1 修改pin脚定义2.5.2 增加串口打印功能2.6 编译代码2.7 debuger 配置参考1. 概述 S32K1系列32位微控制器(MCU)提供基于Arm Cortex-M的MCU,以及基本的…

某PO手机市场竞争分析,巧用波特五力分析法找出核心竞争力!

某PO手机主要从事手机的生产与销售&#xff0c;最近推出了新款 Reno 系列 5G 手机。当前&#xff0c;苹果占据了高端市场&#xff0c;华为占据了中高端市场&#xff0c;而某 PO 手机则在剩余市场中与某 VO 和某米竞争。近年来&#xff0c;某 PO手机凭借中端 R 系列逐步取得市场…

【文献阅读】AdaLora: Adaptive Budget Allocation for Parameter-Efficient Fine-Tuning

目录 1. 前言2. 矩阵分解2.1 SVD分解2.2 特征值分解2.3 LU分解2.4 QR分解 3. AdaLora3.1 motivation3.2 改进 1. 前言 矩阵分解为什么可以加速推理 假设原始权重矩阵 W ∈ R ( m ∗ n ) {W∈R^{(m*n)}} W∈R(m∗n)&#xff0c;矩阵乘法中时间复杂度为mn&#xff0c;变形为 W …

Vue.js 组件化开发:父子组件通信与组件注册详解

Vue.js 组件化开发&#xff1a;父子组件通信与组件注册详解 简介&#xff1a; 在 Vue.js 的开发中&#xff0c;组件是构建应用的重要基础。掌握组件的创建与使用&#xff0c;尤其是父子组件的通信和组件的注册与命名&#xff0c;是开发中不可或缺的技能。本文将详细探讨这些内容…

Day-04-QFile打开文件的两种方式

一、UI界面设置两个按键&#xff0c;并直接转到槽函数 二、两种代码展示 #include <QFile> #include <QDebug>//此两种方式中调用函数&#xff0c;应包含的头文件void Widget::on_btnReadFile01_clicked()//第一种打开方式 {//1. 打开文件QFile file;file.setFile…

双指针(3)_快慢指针_快乐数问题

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 双指针(3)_快慢指针_快乐数问题 收录于专栏【经典算法练习】 本专栏旨在分享学习C的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1.…

天润融通解开售后维修的成本枷锁,提高维修服务效率

如今&#xff0c;企业客户服务在开展业务咨询和售后受理时&#xff0c;主要方式还是通过电话与在线方式进行。这种方式虽然方便&#xff0c;但是对于一些非常紧急的情况还是显得有些不够。 比如&#xff0c;虽然现在许多企业APP已经实现了一键咨询和一键报修&#xff0c;但当客…

[Deepin] 简单使用 RustDesk 实现远程访问Deepin

本教程假设你学会了看官方文档&#xff0c;且拥有基本的IT常识 本教程仅提供可用的方法&#xff0c;并讲述局限性和更优但更复杂的方法&#xff0c;不是一个手把手教程 目标&#xff1a;实现远程访问Deepin 依托 樱花frpRustDesk的“允许通过ip访问” 概述 在RustDesk打开…

谷歌seo网址如何快速被收录?

想让你的网站快速被搜索引擎收录&#xff0c;可以采取几种不同的策略。首先&#xff0c;确保你的网站内容丰富、有价值&#xff0c;搜索引擎更喜欢收录内容质量高的网站。同时&#xff0c;增强网站的外链建设&#xff0c;做好这些站内优化&#xff0c;接下来就是通过谷歌搜索控…

AMV格式转换,试试这五种转换方式

AMV格式转换&#xff0c;AMV格式是一种专为MP4播放器而开发的视频格式&#xff0c;具有小巧、易于传输和较好的视频质量等特点。然而&#xff0c;AMV格式并不是普遍支持的格式&#xff0c;这导致了许多用户在使用MP4播放器时无法播放AMV格式的视频。为了帮助大家解决这一问题&a…

动态化-鸿蒙跨端方案介绍

一、背景 &#x1f449; 华为在2023.9.25官方发布会上宣布&#xff0c;新的鸿蒙系统将不再兼容安卓应用&#xff0c;这意味着&#xff0c;包括京东金融APP在内的所有安卓应用&#xff0c;在新的鸿蒙系统上将无法运行&#xff0c;需要重新开发专门适用于新鸿蒙系统的专版APP。 …

Java项目: 基于SpringBoot+mysql网上点餐系统分前后台(含源码+数据库+答辩PPT+毕业论文)

一、项目简介 本项目是一套基于SpringBootmysql网上点餐系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功能齐…

深度学习特征提取魔改版太强了!发文香饽饽!

要说CV领域经久不衰的研究热点&#xff0c;特征提取可以占一席&#xff0c;毕竟SLAM、三维重建等重要应用的底层都离不开它。 再加上近几年深度学习兴起&#xff0c;用深度学习做特征提取逐渐成了主流&#xff0c;比传统算法无论是性能、准确性还是效率都更胜一筹。 目前比较…

AAC高级音频编码技术

一、什么是AAC AAC的中文名称是高级音频编码技术&#xff0c;它是基于MPEG-2的一种全新的音频编码技术。随着时代的发展&#xff0c;目前AAC的技术升级到MPEG-4表准。AAC广泛的应用在网络传输、高清录制等领域&#xff0c;而AAC技术的出现就是为了取代之前的MP3格式。 二、为什…

类的加载过程与初始化小记

//部分内容来自“狂神说java” 代码验证 解释 1.加载类的信息&#xff0c;加载到内存中&#xff0c;如例子&#xff0c;将Test05和A类的信息加载到方法区&#xff0c; 2.加载完成后&#xff0c;立马生成一个class对象&#xff0c;如例 java.lang.class对象代表Test05类..., 3…

畅捷通ERP远程访问:使用巴比达内网穿透的体验

ERP系统的应用越来越普遍。畅捷通ERP作为一款优秀的企业资源管理工具&#xff0c;帮助企业整合资源&#xff0c;提高运营效率。然而&#xff0c;很多企业在使用畅捷通ERP时&#xff0c;面临着远程访问的问题。为了有效解决这一问题&#xff0c;我尝试了巴比达内网穿透&#xff…