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

news2025/8/11 16:30:26

目录

动态规划理论基础

509. 斐波那契数

思路

斐波那契数

递归思路

动态规划

动态规划(优化数组)

70. 爬楼梯

思路

爬楼梯

动态规划(优化数组)

动态规划(变量替代数组)

746. 使用最小花费爬楼梯

思路

使用最小花费爬楼梯

动态规划(使用数组)

动态规划(使用变量)


动态规划理论基础

        递归算法是一种穷举的展示,任何数学递推公式都可以直接转换成递归算法,递归算法是当前层需要上一层的准备。递归算法冗余计算的增长是爆炸性的。如果编译器的递归模拟算法要是能够保留一个预先算出的值的表,而对已经解过的子问题不用再进行递归调用,那么这种指数式的爆炸性的增长就可以避免

        动态规划就是这样的算法

        如果某一个问题可以解决很多重叠问题,那么使用动态规划是最有效的解决办法

        动态规划中的每一个状态是由上一个状态推导出来的,这和贪心算法是不同的,贪心算法是没有状态推导的过程,贪心算法都是在当前局部选取最优解。所以贪心算法解决不了动态规划的问题

        动态规划五部曲:
                1、确定dp数组(dp table)及下标的含义
                2、确定递推公式
                3、初始化dp数组
                4、确定遍历顺序
                5、举例推导dp数组

509. 斐波那契数

题目链接:力扣

思路

下面是对递归的优化:

        用表优化递归

        从这道题目可以看出,递归算法是需要不断向下进行计算,进行压栈,比如要算F(5),那就要先算出F(4)和F(3),就要先算出F(3)、F(2)、F(2)、F(1)……,这里可以看到是有重复的运算的

        那我们可以先创建一个数组(表),能够保留一个预先算出的值,这样就可以不用,这样就避免了重复的运算。已经算过的F(n)就不用再进行重复的计算

        根据动态规划五部曲:
                1、确定dp数组(dp table)及下标的含义
                        第i个下标存储的是F(i)斐波那契的值
                2、确定递推公式
                        递推公式是:dp[i] = dp[i - 1]+dp[i - 2]
                3、初始化dp数组
                        dp[0] = 0;
                        dp[1] = 1;
                4、确定遍历顺序
                        从递推公式可以得出,后面的数字依赖前面的数字,所以是从前向后遍历
                5、举例推导dp数组
                        0 1 1 2 3 5 8 13 21 34 55

下面是对表的优化:

        得出动态对话的代码之后会发现,代码的内存消耗比较大,我们发现处理,中间过程中的数字不都用,但是还是占用了内存,这样的内存占用时浪费的。比如F(10)。dp数组为:0 1 1 2 3 5 8 13 21 34 55。但是只会返回55,前面的都不用

        其实只需要维护两个数值就可以了,不需要记录整个数列。在整个遍历的过程中
        dp[0] = dp[i - 1]
        dp[1] = dp[i - 2]
        最后循环结束的时候dp[1]就是我们要的值

斐波那契数

递归思路

 

class Solution {
    public int fib(int n) {

        // 终止条件
        if (n <= 1) {
            return n;
        }
    
        return fib(n - 1) + fib(n - 2);
    }
}

动态规划

 

class Solution {
    public int fib(int n) {

        if (n == 0) {
            return 0;
        }
        if (n == 1) {
            return 1;
        }

        // 创建数组
        int[] dp = new int[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];


    }
}

动态规划(优化数组)

class Solution {
    public int fib(int n) {

        if (n <= 1) {
            return n;
        }

        // 创建数组
        int[] dp = new int[2];

        // 初始化数组
        dp[0] = 0;
        dp[1] = 1;

        // 遍历实现数组
        for (int i = 2; i <= n; i++) {
            int sum = dp[0] + dp[1];
            dp[0] = dp[1];
            dp[1] = sum;
        }

        return dp[1];
    }
}

70. 爬楼梯

题目链接:力扣

思路

        本题也是动态规划的简单题,但是从这一道题目就可以发现动态规划的难点就在于去发现递推公司,这道题目本质上是一道斐波那契数列,但是发现并不容易,推导起来也不是很好想

        题目中要求的每次可以爬1或者2个台阶,也就是说,最终到达n阶台阶有两种方式,一个是爬1阶台阶到达(对应的是从n-1阶台阶开始),那么另一个就是爬2阶台阶到达(对应的是从n-2阶台阶开始爬),而爬n-1阶和n-2阶台阶的方法有dp[n - 1],dp[n - 2]个。所以最终爬n阶台阶的方法种类就是dp[n -1 ]+dp[n -2]。其实也就是从n-1和n-2阶爬上去,探究的是几种走法,而不是几步

        台阶   几种方法
           1          1
           2          2
           3          3
           4          5
           5          8

        从二阶到四阶的那二阶一步和从三阶到四阶的一阶一步本身没有产生新方法,所以是从二阶达到四阶和从三阶达到四阶的两种方式相加

        所以推导的过程是:
                在到达第n层的上一步,我们只有两个选择,走一步,或者走两步。
                如果是走一步,我们需要先通过 f(n-1)种方式到达 n-1 层
                如果是走两步, 我们需要通过 f(n-2)种方式到达第 n - 2 层
                所以综上有 f(n) = f(n-2) + f(n-1)

        至于要如何初始化dp[0] = 1还是dp[1] = 1 .我倒觉得这个不是大问题,只不过是在对代码的意义上的解释不同,dp[1] = 1更能体现出动态思路的意义,dp[0] = 1也没啥问题

爬楼梯

动态规划(优化数组)

class Solution {
    public int climbStairs(int n) {

        if (n <= 2) {
            return n;
        }

        // 创建dp数组
        int[] dp = new int[3];

        // 初始化数组
        dp[1] = 1;
        dp[2] = 2;

        // 遍历更新数组
        for (int i = 3; i <= n; i++) {
            int sum = dp[1] + dp[2];
            dp[1] = dp[2];
            dp[2] = sum;
        }

        return dp[2];
    }
}

动态规划(变量替代数组)

class Solution {
    public int climbStairs(int n) {

        if (n <= 2) {
            return n;
        }

        int dp1 = 1;
        int dp2 = 2;

        for (int i = 3; i <= n; i++) {
            int temp = dp1 + dp2;
            dp1 = dp2;
            dp2 = temp;
        }

        return dp2;
    }
}

746. 使用最小花费爬楼梯

题目链接:力扣

思路

        确定dp数组、确定递推公式、初始化dp真的是不容易呀

1、明确数组

        本体要求的是爬到某一台阶需要的最小花费,随意我们明确dp[]数组为 最小花费数组,其中下标i上的数代表到大第 i 层台阶需要花费的最小费用为 dp[i]

2、递推公式

        数组明确之后,就是考虑怎么获取数组中的值,也就是怎么求取每个台阶的最小花费值。这里dp[i] 是有两种情况的
        第一种情况是从前一个台阶跳上来,那最小花费 = 到达前一个台阶的最小花费 + 前一个台阶对应的费用,也就是
dp[i] = dp[i - 1] + cost[i - 1]
        第二种情况是从前两个台阶跳上来,那最小花费 = 到达前两个台阶的最小花费 + 前两个台阶对应的费用,也就是 dp[i] = dp[i - 2] + cost[i - 2]
        那这两种情况中最小的,就是我们要求的当前台阶对应的最小的费用

3、初始化dp数组

        首先要明确一点就是,当站在下标【0】和下标【1】的时候是不消耗费用的,只有向上跳才会消耗费用,所以这里的初始化是比较重要的,要不然后面的结果也就不同了

使用最小花费爬楼梯

动态规划(使用数组)

class Solution {
    public int minCostClimbingStairs(int[] cost) {

        // 定义数组
        int[] dp = new int[cost.length + 1];

        // 初始化数组
        dp[0] = 0;
        dp[1] = 0;

        // 遍历填充dp数组
        for (int i = 2; i < dp.length; i++) {
            dp[i] = Math.min(dp[i-1] + cost[i-1],dp[i -2] + cost[i-2]);
        }

        return dp[cost.length];
    }
}

动态规划(使用变量)

class Solution {
    public int minCostClimbingStairs(int[] cost) {

        // 初始化
        int dp0 = 0;
        int dp1 = 0;

        // 遍历更新
        for (int i = 2; i <= cost.length; i++) {

            int dpi = Math.min(dp1 + cost[i-1],dp0 + cost[i-2]);
            dp0 = dp1;
            dp1 = dpi;
        }

        return dp1;
    }
}

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

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

相关文章

顺风车用户最爱“送花”城市Top30 出炉,来看有没有你的家乡?

11月18日&#xff0c;嘀嗒小红花迎来“一周岁生日”&#xff0c;嘀嗒出行也于当日正式发布《嘀嗒小红花一周年出行人文报告》。《报告》显示&#xff0c;自2021年11月18日&#xff0c;嘀嗒出行“送你一朵小红花”产品功能上线至今&#xff0c;嘀嗒顺风车乘客已向车主送出239万朵…

商品720vr全景环物制作便捷推送到全世界

720vr全景的应用范围也得到了扩大和普及。VR全景作为新一代信息技术&#xff0c;相较于传统的图文视频等展现方式而言&#xff0c;VR全景不仅能够帮助用户随时随地身临其境的进行沉浸式体验&#xff0c;也可以帮助商家有效降低宣传推广成本。 720VR全景制作拍摄VR全景需要用到相…

德国药品数据库查询系统(含网址)

德国曾经有被誉为世界’医药基地’的称号。在2020年时德国药品出口额有近千亿美元&#xff0c;占世界药品出口总额的近七分之一&#xff0c;连续18年为居世界第一位&#xff0c;不仅仅是销量&#xff0c;德国生物医药行业在心脏、血液循环、糖尿病、癌症等疾病的研究、预防、基…

用Python计算点估计预测评价指标(误差指标RMSE、MSE、MAE、MAPE) ,画图展示

机器学习的回归问题常用RMSE&#xff0c;MSE, MAE,MAPE等评价指标&#xff0c;还有拟合优度R2。由于每次预测出来的预测值再去和原始数据进行误差评价指标的计算很麻烦&#xff0c;所以这里就直接给出他们五个指标的计算函数。把每次预测出来的值和真实值输入这个函数就可以得到…

对话钱江机器人丨国产化破风,谁动了工业机器人厂商的“奶酪”?

工业机器人的研发、制造和应用是衡量一国科技创新和高端制造水平的重要标志&#xff0c;是“制造业皇冠顶端的明珠”&#xff0c;亦是硬科技技术行列中的“课代表”。 《中国机器人产业发展报告&#xff08;2022年&#xff09;》预计&#xff0c;2022年全球机器人市场规模将达…

抗心血管疾病、内分泌信号通路等小分子化合物库介绍

心血管疾病 不少人认为经常熬夜&#xff0c;工作压力大是猝死的主要原因&#xff0c;其实猝死的根本原因是心血管突发病。 心血管疾病是心脏和血管疾病的统称&#xff0c;主要包括冠心病&#xff0c;脑血管疾病&#xff0c;周围末梢动脉血管疾病&#xff0c;先天性心脏病及深…

快速排序图文详细教程

文章目录 文章目录文章目录[toc]一、快排思路二、相关代码小细节改进版本一版本二一、快排思路 还记得之前的荷兰国旗问题吗&#xff08;快排的前身&#xff1a;详解荷兰国旗问题&#xff09;&#xff0c;快排其实就是借助这种思路&#xff0c;在每次遍历中以第一个数作为目标…

[模型部署]:深度学习模型部署(已更Pytorch篇)

模型部署一、Pytorch 模型部署1. 模型保存1.1. 使用torch.save()保存1.2. 使用[torch.jit.save()](https://pytorch.org/docs/stable/generated/torch.jit.save.html)保存2. 模型部署 or 模型编译2.1. TorchScript部署2.2. TensorRT部署2.3. TVM部署2.4. Laser部署模型部署 一…

STM32 GD32 标准库移植SFUD

本次移植是在官方源码的基础上进行移植的 本次介绍的两个软件包SFUD/FAL都与FLASH有关&#xff0c;并且都可以独立使用或者结合在一起使用&#xff0c;两个软件包都对操作系统无依赖&#xff0c;可以使用裸机移植&#xff0c;也很方便移植到各种系统。 这两个软件包的作者都是…

Java JDK安装与配置

Java JDK安装与配置 JDK下载 下载地址&#xff1a;JDK下载 最上方是JDK最新版&#xff0c;往下滑将看到最常用的稳定版本&#xff1a;JDK8 选择版本 勾上选框&#xff0c;点击下载 登录Oracle账号&#xff1a; 没有账号可注册或网上寻找账号&#xff0c;建议自行注册登录成功…

我应该是懂居家办公的吧?

近期的广州疫情十分严峻&#xff0c;海珠区&#xff0c;公司那边的地铁停了。 于是成为了一个【天选居家人】。 天河这边还好一点&#xff0c;起码可以下楼做核酸&#xff0c;买菜&#xff0c;拿快递&#xff0c;出入凭24h核酸。 有人说&#xff1a;以前在公司工作总盼望居家办…

Win10配置IIS与 C#/.net项目的发布与IIS部署

1、IIS配置安装 已经安装IIS的可以跳过 在左下搜索框搜索 “启用或关闭windows功能” 点开&#xff0c;勾选如下图所示勾选框后&#xff0c;点击“确定”后进行安装。 安装完成。在搜索框搜索输入IIS&#xff0c;如图&#xff0c;打开IIS应用。 打开后如图所示 2、在VS中打包…

详解c++----类和对象(二)

目录标题前言为什么会有默认成员函数有哪些默认成员函数构造函数和析构函数为什么会有这两个函数构造函数的简介构造函数的调用构造函数的重载构造函数的缺省参数析构函数的简介析构函数的特性析构函数的例子重回构造函数第一点第二点究竟什么是默认构造函数默认构造函数所带来…

Wnt 信号通路

Wnt 信号通路是一种古老的、进化上保守的通路。其中&#xff0c;Wnt 蛋白属于分泌的糖蛋白&#xff0c;可与卷曲蛋白 (Frizzled) 家族的受体&#xff0c;如与脂蛋白受体相关的蛋白 5/6 (LRP5/6)&#xff0c;Ror2 和 Ryk 相互作用&#xff0c;导致各种细胞内信号传导级联激活&am…

【创建小程序】微信如何创建小程序?

说起我们日常所使用的微信&#xff0c;大家一定也会联想到微信小程序。微信小程序跟微信一样拥有着很高的使用频率&#xff0c;而且微信小程序也成为了很多企业商家除了网站APP以外的必备轻应用。那么在微信如何创建小程序呢&#xff1f;下面给大家简单说说。 一、准备好小程序…

如何优雅地校验后端接口数据,不做前端背锅侠

背景 最近新接手了一批项目&#xff0c;还没来得及接新需求&#xff0c;一大堆bug就接踵而至&#xff0c;仔细一看&#xff0c;应该返回数组的字段返回了 null&#xff0c;或者没有返回&#xff0c;甚至返回了字符串 "null"&#xff1f;&#xff1f;&#xff1f; 这…

【BOOST C++ 13 并行编程】(5) Boost.Atomic

一、说明 Boost.Atomic 提供类 boost::atomic&#xff0c;可用于创建原子变量。它们被称为原子变量&#xff0c;因为所有访问都是原子的。 Boost.Atomic 用于多线程程序&#xff0c;当在一个线程中访问变量不应被访问相同变量的另一个线程中断时。如果没有 boost::atomic&#…

Windows取证——隐藏用户

前言&#xff1a; 实验环境&#xff1a;Windows server 2019 实验目的&#xff1a;了解Windows隐藏账户的工作原理&#xff0c;有针对性地对隐藏账户进行应急处置。 目录 前言&#xff1a; 一、隐藏用户的建立 二、查看隐藏用户 法一&#xff1a;计算机管理本地用户和组查看…

Java集合(复习)

Java中的集合 Java中的集合概述Collection 接口中常用的方法Iterator 迭代器forEach 增强for循环Collection子接口之一&#xff1a;List 接口ArrayList 源码分析LinkedLIst 源码分析Vector 源码分析List 接口常用的方法Collection 子接口之二&#xff1a; Set 接口HashSetLinke…

OnlineJudge平台(负载均衡)

文章目录1.所用技术与开发环境2.项目宏观结构3.compiler服务设计4. 基于MVC结构的oj服务设计5. 前端页面设计6 安装指南升级 gcc安装 jsoncpp安装 cpp-httplib安装boost库安装与测试 ctemplate使用Ace在线编辑器&#xff08;直接复制粘贴即可&#xff09;在线OJ样例题目MySQL 建…