代码随想录刷题笔记 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;通常把这类攻击称为截获。 主动攻击 篡改 攻击者故意篡改网络上传送的报文 恶意程序 拒绝服…

InnoDB索引与优化篇(5)-InnoDB中的查询优化策略

InnoDB是MySQL数据库中一种常用的存储引擎&#xff0c;它具有高性能和可靠性。查询优化是数据库开发中非常重要的一环&#xff0c;它能够帮助我们提高数据库查询的效率和性能。在本篇博客中&#xff0c;我们将介绍一些在使用InnoDB存储引擎时进行查询优化的常用策略&#xff0c…

贪心 Leetcode 455 分发饼干

分发饼干 Leetcode 455 学习记录自代码随想录 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这是能让孩子们满足胃口的饼干的最小尺寸&#xff1…

神经网络算法:卷积神经网络

神经网络算法&#xff0c;也称为人工神经网络算法&#xff0c;是一种模仿人脑神经网络结构和功能的计算模型。它由多个神经元相互连接而成的网络组成&#xff0c;每个神经元都有输入和输出&#xff0c;并通过学习算法来调整连接权重&#xff0c;从而实现对输入数据的模式识别和…

JavaScript Web Socket 详解

Web Socket ​ Web Socket&#xff08;套接字&#xff09;的目标是通过一个长时连接实现与服务器全双工、双向的通信。在 JavaScript 中创建 Web Socket 时&#xff0c;一个 HTTP 请求会发送到服务器以初始化连接。服务器响应后&#xff0c;连接使用 HTTP 的 Upgrade 头部从 H…

12、窗口看门狗

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

数据结构 栈和队列 力扣例题AC——代码以及思路记录

20. 有效的括号 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有一个对应…

mysql使用连接池

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、mysql连接池&#xff1f;二、使用步骤1.引入库 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff1a; 提示&#xff1a…

深入理解Flutter中的StreamSubscription和StreamController

在Flutter中&#xff0c;StreamSubscription和StreamController是处理异步数据流的重要工具。它们提供了一种方便的方式来处理来自异步事件源的数据。本文将深入探讨它们的区别以及在实际应用中的使用场景。 StreamSubscription StreamSubscription代表了对数据流的订阅&…

代码随想录算法训练营番外 刷题日记0301 || 29、两数相除,31、下一个排列

29、两数相除 思路&#xff1a;不断相减就是求解的最直接方法&#xff0c;我这样计算时间复杂度有点高 // 时间复杂度O(count*divisor) // 空间复杂度O(1)class Solution {int res 0;public int divide(int dividend, int divisor) {// dividend 是被除数if(dividend 0) …

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

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

随记-点选验证码

文字验证码&#xff08;点击文字&#xff09; 模板匹配&#xff08;从一张图片中寻找 icon&#xff09;&#xff0c;放弃&#xff0c;目前准确率不高&#xff0c;且处理过程复杂 灰度处理将 complete_image_path 截取并另存为 target_image_path&#xff0c; verify_image_path…

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

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

c++知识点之 --this

在成员函数中存在。struct和class每个成员函数都隐含一个名为this的指针形参&#xff0c;并且它是该成员函数的第一个参数&#xff0c;当某个对象调用成员函数时&#xff0c;就会把该对象的地址传给被调用成员函数的隐式形参this。 this是一个指针 &#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…