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

文章目录

    • 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.mzph.cn/news/713713.shtml

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

相关文章

ECMAScript-262 @2023版本中的关键字和保留字

1、什么是标识符&#xff1f; 所谓标识符&#xff0c;就是javascript里的变量、函数、属性或函数参数的名称&#xff0c;可由一个或多个字符组成&#xff0c;当然标识符有命名规范 标识符第一个字符必须是 一个字母、下划线&#xff08;_&#xff09;或美元符号&#xff08;$…

ONLYOFFICE文档8.0全新发布:私有部署、卓越安全的协同办公解决方案

ONLYOFFICE文档8.0全新发布&#xff1a;私有部署、卓越安全的协同办公解决方案 文章目录 ONLYOFFICE文档8.0全新发布&#xff1a;私有部署、卓越安全的协同办公解决方案摘要&#x1f4d1;引言 &#x1f31f;正文&#x1f4da;一、ONLYOFFICE文档概述 &#x1f4ca;二、ONLYOFFI…

【新书推荐】10.2 分支程序设计

稍微复杂一些的程序通常需要做某种条件判断&#xff0c;然后再决定程序的执行流程。当然也可以无条件跳转到程序的另一处地址开始执行。本节我们将详细介绍分支结构的程序设计方法。 针对功能较为复杂的程序&#xff0c;程序开发有一套标准的流程&#xff0c;我们将10.1节中的五…

计算机网络【网络安全】

计算机网络——网络安全 一、网络安全问题概述 网络安全威胁 网络安全面临两大类威胁&#xff0c;被动攻击和主动攻击 被动攻击 指攻击者从网络上窃听他人的通信内容&#xff0c;通常把这类攻击称为截获。 主动攻击 篡改 攻击者故意篡改网络上传送的报文 恶意程序 拒绝服…

12、窗口看门狗

目录 1、窗口看门狗概述 2、常用寄存器和库函数配置 3、窗口看门狗实验 1、窗口看门狗概述 之所以称为窗口就是因为其喂狗时间是一个有上下限的范围内&#xff08;窗口&#xff09;&#xff0c;你可以通过设定相关寄存器&#xff0c;设定其上限时间&#xff08;下限固定&…

技术栈选型的时候,ruby、go、java、vue、react应该怎么选择?

选择适合项目需求、团队技术背景和偏好、开发速度、性能要求以及可扩展性的技术栈和框架是一个综合考虑的过程&#xff0c;没有一种通用的最佳选择&#xff0c;取决于具体情况。 选择Vue.js或React应该综合考虑项目的需求、团队的技术背景和偏好、生态系统的支持和发展趋势等因…

WPF真入门教程30--顺风物流单据管理系统

1、教程回顾 到现在为止&#xff0c;真入门系列教程已完成了29刺由浅入深地讲解&#xff0c;当然不可能讲到了WPF的所有技能点&#xff0c;但读者看到了wpf的内部各种功能及之间的联系&#xff0c;在此基础上&#xff0c;提供一个完整有效的综合项目&#xff0c;本项目采用的是…

加密与安全_深入了解Hmac算法(消息认证码)

文章目录 PreHMAC概述常见的Hmac算法Code随机的key的生成 KeyGeneratorHmacMD5用Hmac算法取代原有的自定义的加盐算法 HmacMD5 VS MD5HmacSHA256 Pre 加密与安全_深入了解哈希算法中我们提到&#xff0c; 存储用户的哈希口令时&#xff0c;要加盐存储&#xff0c;目的就在于抵…

操作系统系列学习——CPU管理的直观想法

文章目录 前言CPU管理的直观想法 前言 一个本硕双非的小菜鸡&#xff0c;备战24年秋招&#xff0c;计划学习操作系统并完成6.0S81&#xff0c;加油&#xff01; 本文总结自B站【哈工大】操作系统 李治军&#xff08;全32讲&#xff09; 老师课程讲的非常好&#xff0c;感谢 【…

OpenLayers线性渐变和中心渐变(径向渐变)

目录 1.前言2.添加一个面要素3.线性渐变3.1 第一个注意点3.2 第二个注意点 4.中心渐变&#xff08;径向渐变&#xff09;5.总结 1.前言 OpenLayers官网有整个图层的渐变示例&#xff0c;但是没有单个要素的渐变示例&#xff0c;我们这里来补充一下。OpenLayers中的渐变是通过fi…

编译链接实战(22)C/C++代码覆盖率统计报告生成

文章目录 GCOV 工具简介gcov 使用lcov相关编译选项 GCOV 工具简介 gcov是一个测试代码覆盖率的工具&#xff0c;它是 gcc 自带的查看代码覆盖率的工具。 与GCC结合使用&#xff0c;可以分析您的程序以帮助创建更高效、运行更快的代码&#xff0c;并发现程序中未经测试的部分。…

PCIE 4.0 L0s/L1/L2

L0是PCIE设备正常工作的状态&#xff0c;当设备链路处于非工作状态可以跳转大相应的低功耗状态&#xff0c;L0s是一种可以快速恢复到L0的低功耗状态&#xff1b;L1必须经过Reovery状态才可以恢复到L0状态&#xff1b;L2需要从Detect开始逐步进入到L0状态。它们的恢复时间依次延…

麒麟银河操作系统V10部署ffmpeg(也能用于Linux系统)

麒麟银河操作系统V10部署ffmpeg(也能用于Linux系统) 部署ffmpeg用来处理视频的各种操作 想使用ffmpeg&#xff0c;要先安装nasm&#xff0c;yasm&#xff0c;x264之后&#xff0c;否则会报错 nkvers 查看麒麟操作系统版本 cat /proc/version #查看linux版本信息 uname -a …

Android修行手册-Chaquopy中opencv、numpy的初步应用

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

SpringBoot源码解读与原理分析(三十八)SpringBoot整合WebFlux(一)WebFlux的自动装配

文章目录 前言第13章 SpringBoot整合WebFlux13.1 响应式编程与Reactor13.1.1 命令式与响应式13.1.2 异步非阻塞13.1.3 观察者模式13.1.4 响应性13.1.5 响应式流13.1.6 背压13.1.7 Reactor13.1.7.1 Publisher13.1.7.2 Subscriber13.1.7.3 Subscription13.1.7.4 Processor13.1.7.…

Leetcoder Day32| 贪心算法part05

763.划分字母区间 字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。 示例&#xff1a; 输入&#xff1a;S "ababcbacadefegdehijhklij"输出&#xff1a;[9,7…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 3月2日,星期六

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年3月2日 星期六 农历正月廿二 1、 气象局&#xff1a;3月份仍有5次冷空气影响我国&#xff1b;全国多地或提前入春。 2、 央行&#xff1a;将外籍来华人员移动支付单笔交易限额由1000美元提高到5000美元。 3、 神舟十七号航…

【源码】imx6ull实现触摸屏单点实验

一、本实验实验的器材&#xff1a; 1.正点原子imx6ull的阿尔法开发板v2.2 2.屏幕ALIENTEK 4.3 RGBLCD 二、实验已经移植好的文件&#xff1a; 仓库代码&#xff1a;https://gitee.com/wangyoujie11/atkboard_-linux_-driver.git 1.文件说明 23_multitouch &#xff1a;驱动代…

【YOLO v5 v7 v8 小目标改进】ODConv:在卷积核所有维度(数量、空间、输入、输出)上应用注意力机制来优化传统动态卷积

ODConv&#xff1a;在卷积核所有维度&#xff08;数量、空间、输入、输出&#xff09;上应用注意力机制来优化传统的动态卷积 提出背景传统动态卷积全维动态卷积效果 小目标涨点YOLO v5 魔改YOLO v7 魔改YOLO v8 魔改 论文&#xff1a;https://openreview.net/pdf?idDmpCfq6Mg…

leedcode刷题--day7(字符串)

23 文章讲解 力扣地址 C class Solution { public:void reverseString(vector<char>& s) {int left 0;int right s.size() - 1; // right 应该初始化为 s.size() - 1while (left < right) {swap(s[left], s[right]); // 直接交换 s[left] 和 s[right] 的值lef…