代码随想录刷题笔记 DAY 37 | 动态规划理论基础 | 斐波那契数 No.509 | 爬楼梯 No.70 | 使用最小花费爬楼梯 No.746

news2024/9/20 0:53:10

文章目录

    • Day 37
      • 00. 动态规划理论基础
      • 01. 斐波那契数(No. 509)
        • <1> 题目
        • <2> 笔记
        • <3> 代码
      • 02. 爬楼梯(No. 70)
        • <1> 题目
        • <2> 笔记
        • <3> 代码
      • 03. 使用最小花费爬楼梯(No. 746)
        • <1> 题目
        • <2> 笔记
        • <3> 代码

Day 37

00. 动态规划理论基础

最常见的动态规划题目其实就是 求最值,比如说股票问题、背包问题,都是在求使用怎样的策略能使得整个系统达到一个最优化的状态。

这是否和贪心比较类似呢?

其实贪心算法和动态规划算法的区别还是比较大的,贪心算法每一次的最优解一定 包含 上一次的最优解,是局部的最优推出全局的最优,而动态规划的最优解不一定包含前一次的最优解,而是有可能是由更前面的部分推出的,所以通常通过 dp[] 数组来将前面的所有最优解来保存下来。

动态规划其实是一个 穷举 的过程,得到最优解的前提就是要将所有的可能导致最优解的情况列出来,逐步推出最终的结果,而贪心更像是确定了一个路线,直接来走这个最优的路线,但这种最优通常是一种经验性的,较难推导的方式,相信做过贪心部分的朋友应该深有体会,这也就导致贪心得到的可能不是最优解,但相对的时间复杂度较低,而动态规划本质是穷举就会导致其时间复杂度相对较高。

再来谈谈动态规划和暴力解法的区别,比如说斐波那契数列,使用递归来求会导致大量的重复计算,所以考虑引入备忘录,也就是记忆搜索的方法,记忆搜索的方法是自顶向下的,也就是要算 f(5) 要递归到 f(1) 才开始计算结果,而且由于递归的限制,思考其实可以采用自底向下的方式,从 f(1) 开始向上层递归,这其实就是动态规划的方法。

01. 斐波那契数(No. 509)

题目链接

代码随想录题解

<1> 题目

斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 01 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1

给定 n ,请计算 F(n)

示例 1:

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

示例 2:

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

示例 3:

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

提示:

  • 0 <= n <= 30
<2> 笔记

这道题目相信大家都能比较容易的写出来,这里以本题为案例看看动态规划的一些小特点。

动态规划比较重要的一个点就是 状态,解题的关键在于能否列出正确的 状态转移方程,以及这个状态转移方程最终能否穷举出问题的最终答案,其实这就要求这个算法问题具备 最优子结构;因为需要不断用到前面的状态来推导后面状态的最优,这就会引出大量的重复的计算这也就是常说的 重叠子问题,所以使用暴力解法的效率很低。

这道斐波那契数列其实就很好的展示了重叠子问题,但其实并不存在重叠子问题,所以严格上并不算动态规划的题目。

比如计算 f(5),画出递归树

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可以看出其实是计算了两遍 f(3) 的,如果说计算的数字更大,子问题的个数会以指数级的速度增长,时间复杂度为 2n。这就是所谓的重叠子问题。

可以注意到 f(n) 的状态其实是由 f(n - 1)f(n - 2) 推导出来的,转移的方式其实就是两者加和,这样其实就很容易看出 dp 数组的含义,就是 dp[n] = f(n),状态转移公式也顺带推了出来(这就是本题较为简单的原因),因为这几步几乎不用怎么思考。

直接写出代码。

<3> 代码
class Solution {
    public int fib(int n) {
        if (n == 0) return 0;
        if (n <= 2) return 1;
        int[] dp = new int[n + 1];
        dp[1] = 1;
        dp[2] = 1;
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}

02. 爬楼梯(No. 70)

题目链接

代码随想录题解

<1> 题目

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

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

示例 1:

输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。

  1. 1 阶 + 1 阶
  2. 2 阶

示例 2:

输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。

  1. 1 阶 + 1 阶 + 1 阶
  2. 1 阶 + 2 阶
  3. 2 阶 + 1 阶

提示:

  • 1 <= n <= 45
<2> 笔记

本题其实也没有引入太多的递归思想,其实可以看作是下一题 使用最小花费爬楼梯 的一个导入。

本题的 dp 定义其实是较为简单的,因为要得出 n 阶台阶由几种走法,可以想到就是用 dp[n] 来代表共 n 阶由多少种走法。

爬到第一层楼有一种方法,爬到第二层有两种方法,那爬到第三层其实就有三种方法,一种是通过第一层跨两步,另一种是第二层跨一步。

很多朋友做这道题的时候会有一个疑问的地方,就是我从第一层走一步再走一步算不算一种方法呢?或者说从第四层走两次到第五层,这里想不通的朋友是因为没有将目光放到全局,其实将这些方式写出来得到的数列是相同的,比如 n = 3 的时候 1 1 1,可以理解成从 2 到 3 的一部分,也可以理解成从 1 跨两步到 3,计算的话其实就计算其中的一部分即可,否则会出现冲突。

使用递归五步法来规范一下:

  1. 确认 dp 的含义:爬到第i层楼梯,有dp[i]种方法
  2. 确认递推公式:dp[i] = dp[i - 1] + dp[i - 2]
  3. dp 数组如何初始化:题目中说了n是一个正整数,所以 dp[0] 是没有意义的,而递归推出后面的部分有需要两个元素,所以初始化就初始化 dp[1]dp[2]
  4. 递归的遍历顺序:需要用到前面的元素,从前向后遍历
  5. 尝试举例推导
<3> 代码
class Solution {
    public int climbStairs(int n) {
        if (n < 3) return n;
        int[] dp = new int[n + 1];
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2]; 
        }
        return dp[n];
    }
}

03. 使用最小花费爬楼梯(No. 746)

题目链接

代码随想录题解

<1> 题目

给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。

你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

请你计算并返回达到楼梯顶部的最低花费。

示例 1:

输入:cost = [10,15,20]
输出:15
解释:你将从下标为 1 的台阶开始。

  • 支付 15 ,向上爬两个台阶,到达楼梯顶部。
    总花费为 15 。

示例 2:

输入:cost = [1,100,1,1,1,100,1,1,100,1]
输出:6
解释:你将从下标为 0 的台阶开始。

  • 支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。
  • 支付 1 ,向上爬两个台阶,到达下标为 4 的台阶。
  • 支付 1 ,向上爬两个台阶,到达下标为 6 的台阶。
  • 支付 1 ,向上爬一个台阶,到达下标为 7 的台阶。
  • 支付 1 ,向上爬两个台阶,到达下标为 9 的台阶。
  • 支付 1 ,向上爬一个台阶,到达楼梯顶部。
    总花费为 6 。

提示:

  • 2 <= cost.length <= 1000
  • 0 <= cost[i] <= 999
<2> 笔记

有了上一道题的铺垫其实本题就比较容易了,到达台阶 n 有两种方式分别是从 n - 1n - 2 到达,所以需要有一个数组来存储之前的状态。

  1. 确定dp数组以及下标的含义,使用动态规划,就要有一个数组来记录状态,本题只需要一个一维数组dp[i]就可以了,dp[i]的定义:到达第i台阶所花费的最少体力为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] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
  3. dp 数组如何初始化:和上面题目相同,只需要初始化两个即可,也就是 dp[0]dp[1],分别初始化成 cost[0]ocst[1]
  4. 确定遍历顺序:和上题相同,都是自底向上,从前向后遍历
  5. 举例推导,发现没有问题

通过上面的梳理就能写出代码

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

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

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

相关文章

Project_Euler-44 题解

Project_Euler-44 题解 题目 思路 题目给出了一个性质&#xff0c;让我在对应性质的数据中找出目标值&#xff0c;这种问题首先想到的就是枚举。 我们可以枚举 P k P_k Pk​ &#xff0c;对于每一个 P k P_k Pk​ &#xff0c;我们再枚举 P j P_j Pj​&#xff0c; P j P_…

阿尔卡特Adixen ADP/ADS 系列 2 干泵使用说明

阿尔卡特Adixen ADP/ADS 系列 2 干泵使用说明

《求生之路2》服务器如何选择合适的内存和CPU核心数,以避免丢包和延迟高?

根据求生之路2服务器的实际案例分析选择合适的内存和CPU核心数以避免丢包和延迟高的问题&#xff0c;首先需要考虑游戏的类型和对服务器配置的具体要求。《求生之路2》作为一款多人在线射击游戏&#xff0c;其服务器和网络优化对于玩家体验至关重要。 首先&#xff0c;考虑到游…

Android修行手册-集成Python开发环境

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

redis实现分布式全局唯一id

目录 一、前言二、如何通过Redis设计一个分布式全局唯一ID生成工具2.1 使用 Redis 计数器实现2.2 使用 Redis Hash结构实现 三、通过代码实现分布式全局唯一ID工具3.1 导入依赖配置3.2 配置yml文件3.3 序列化配置3.4 编写获取工具3.5 测试获取工具 四、运行结果 一、前言 在很…

PySide6+VSCode Python可视化环境搭建

#记住在cmd中运行&#xff0c;不要在vscode里运行&#xff0c;否则env会装到工程目录下 python -m venv env #env\Scripts\activate.bat pip install pyside6 下载本期源码 vscode装一个PYQT Integration插件&#xff0c;设置好两个路径&#xff08;下面有个脚本用于获取路径&…

陶瓷工业5G智能制造工厂数字孪生可视化平台,推进行业数字化转型

陶瓷工业5G智能制造工厂数字孪生可视化平台&#xff0c;推进行业数字化转型。在陶瓷工业领域&#xff0c;5G智能制造工厂数字孪生可视化平台的应用正在改变着行业的传统生产模式&#xff0c;推动着数字化转型的进程。本文将围绕这一主题展开探讨&#xff0c;分析数字孪生可视化…

Socket网络编程(四)——点对点传输场景方案

目录 场景如何去获取到TCP的IP和Port&#xff1f;UDP的搜索IP地址、端口号方案UDP搜索取消实现相关的流程&#xff1a;代码实现逻辑服务端实现客户端实现UDP搜索代码执行结果 TCP点对点传输实现代码实现步骤点对点传输测试结果 源码下载 场景 在一个局域网当中&#xff0c;不知…

Win11系统安装安卓子系统教程

随着Win11系统的不断普及&#xff0c;以及硬件设备的更新换代&#xff0c;我相信很多同学都已经更新并使用到了最新的Win11系统。那么&#xff0c;Win11系统最受期待的功能“Windows Subsystem for Android”&#xff08;简称WSA&#xff09;&#xff0c;即《安卓子系统》。他可…

CAPL组装IPv4分片包的三种思路(2)

2、使用CAPL的函数自动生成一条完整的ICMPv4 Echo Request报文,然后把数据手动放入两个分片报文中 首先生成一条完整的icmp报文: ethernetPacket ppkt1;//icmpv4 echo requestbyte data[1] = {10};//icmpv4 echo request datappkt1.icmpv4.echo…

湖南湘菜 7页面 美食主题 带设计说明 美食网页设计制作 HTML美食网页成品 美食网页成品 HTML美食网页设计

湖南湘菜 7页面 美食主题 带设计说明 jquery图片轮播特效 滚动文字 aspaccess数据库注册登录留言功能 美食网页设计制作 HTML美食网页成品 美食网页成品 HTML美食网页设计制作 前端美食网页开发 热门美食特产网页制作 静态网页成品 asp/php动态网站设计制作DW定制定做 web前…

佛山50公里徒步组团|真北敏捷社区佛山敏捷DevOps社区

真北敏捷社区&佛山敏捷DevOps社区有两个宗旨&#xff0c;一是求知&#xff0c;二是连接。连接有识之士&#xff0c;同修友士之识。峨峨乎高山&#xff0c;洋洋乎流水。谈笑有鸿儒&#xff0c;往来无白丁。 《柳叶刀》上的研究显示&#xff0c;运动的情绪价值&#xff0c;相…

GitHub Copilot extension activation error: ‘No access to GitHub Copilot found‘

好不容易学生认证通过了&#xff0c;打开vscode用copilot结果一直报这个错误。我的原因是&#xff1a;还未给copilot授权&#xff0c; 通过了学生认证后要进入这里进行授权&#xff1a;

数据分析-Pandas数据探查初步圆饼图

数据分析-Pandas数据探查初步圆饼图 数据分析和处理中&#xff0c;难免会遇到各种数据&#xff0c;那么数据呈现怎样的规律呢&#xff1f;不管金融数据&#xff0c;风控数据&#xff0c;营销数据等等&#xff0c;莫不如此。如何通过图示展示数据的规律&#xff1f; 数据表&am…

PHP使用imap_open读取QQ邮箱

PHP代码&#xff1a; /** PHP使用imap_open读取QQ邮箱imap_open 官方文档&#xff1a;https://www.php.net/function.imap_open */function parse_mailstr($subject) {$a explode(?,$subject);$n count($a);$a $a[$n-2];return base64_decode($a); }function recevie_emai…

点亮城市名片丨计讯物联智慧灯杆系统在通讯基地的成功应用

项目背景 在国家新型城镇化大背景下&#xff0c;十四五规划纲要强调“加快数字化发展&#xff0c;建设数字中国”&#xff0c;明确提出“以数字化助推城乡发展和治理模式创新”&#xff0c;全面提高城市的运行效率和宜居程度。 项目概况 为满足灯杆灯光亮度的远程智能管理、对…

docker构建hyperf环境

一&#xff0c;构建hyperf 镜像 官网git https://github.com/hyperf/hyperf-docker 使用dockerfile构建镜像 根据需要这里我使用8.1 swoole版本的镜像 在/home/hyperfdocker 目录中新建一个Dockerfile文件&#xff0c;将这个git上的Dockerfile内容复制粘贴进去 docker build…

Linux--使用 Haproxy搭建Web群集

1、 案例概述 Haproxy是目前比较流行的一种群集调度工具&#xff0c;同类群集调度工具有很多&#xff0c;如LVS 和 Nginx。相比较而言&#xff0c;LVS性能最好&#xff0c;但是搭建相对复杂&#xff1a;Nginx的upstream 模块支持群集功能&#xff0c;但是对群集节点健康检查功能…

java 基础上(1)(核心知识搭配代码)

前言 java的学习分为了上部分以及下部分进行学习&#xff0c;上部分就是对于java的基础知识&#xff0c;面向对象上&#xff0c;面向对象下&#xff0c;异常操作&#xff0c;javaApi&#xff1b;下部主要是集合&#xff0c;泛型&#xff0c;反射&#xff0c;IO流&#xff0c;J…

Ubuntu篇——crontab修改编辑器

输入命令: crontab -e 如果你的系统是第一次使用crontab服务&#xff0c;会首先让你选择一个编辑器 如果已经选择过编辑器&#xff0c;后续想要修改默认编辑器&#xff0c;可以输入sudo select-editor进行修改。