面试算法88:爬楼梯的最少成本

题目

一个数组cost的所有数字都是正数,它的第i个数字表示在一个楼梯的第i级台阶往上爬的成本,在支付了成本cost[i]之后可以从第i级台阶往上爬1级或2级。假设台阶至少有2级,既可以从第0级台阶出发,也可以从第1级台阶出发,请计算爬上该楼梯的最少成本。例如,输入数组[1,100,1,1,100,1],则爬上该楼梯的最少成本是4,分别经过下标为0、2、3、5的这4级台阶,如图14.1所示(注意:最上一级台阶是没有成本的)。
在这里插入图片描述

分析

分析1

爬上一个有多级台阶的楼梯自然需要若干步。按照题目的要求,每次爬的时候既可以往上爬1级台阶,也可以爬2级台阶,也就是每一步都有两个选择。这看起来像是与回溯法有关的问题。但这个问题不是要找出有多少种方法可以爬上楼梯,而是计算爬上楼梯的最少成本,即计算问题的最优解,因此解决这个问题更适合运用动态规划。

分析2:确定状态转移方程

这个问题要求计算爬上楼梯的最少成本,可以用函数f(i)表示从楼梯的第i级台阶再往上爬的最少成本。如果一个楼梯有n级台阶(台阶从0开始计数,从第0级一直到第n-1级),由于一次可以爬1级或2级台阶,因此最终可以从第n-2级台阶或第n-1级台阶爬到楼梯的顶部,即f(n-1)和f(n-2)的最小值就是这个问题的最优解。
应用动态规划的第1步是找出状态转移方程,即用一个等式表示其中某一步的最优解和前面若干步的最优解的关系。根据题目的要求,可以一次爬1级或2级台阶,既可以从第i-1级台阶爬上第i级台阶,也可以从第i-2级台阶爬上第i级台阶,因此,从第i级台阶往上爬的最少成本应该是从第i-1级台阶往上爬的最少成本和从第i-2级台阶往上爬的最少成本的较小值再加上爬第i级台阶的成本。这个关系可以用状态转移方程表示为f(i)=min(f(i-1),f(i-2))+cost[i]。

分析3

上述状态转移方程有一个隐含的条件,即i大于或等于2。如果i小于2怎么办?如果i等于0,则可以直接从第0级台阶往上爬,f(0)等于cost[0]。如果i等于1,题目中提到可以从第1级台阶出发往上爬,因此f(1)等于cost[1]。

public class Test {public static void main(String[] args) {int[] cost = {1, 100, 1, 1, 100, 1};int result = minCostClimbingStairs(cost);System.out.println(result);}public static int minCostClimbingStairs(int[] cost) {int len = cost.length;return Math.min(helper(cost, len - 2), helper(cost, len - 1));}private static int helper(int[] cost, int i) {if (i < 2) {return cost[i];}return Math.min(helper(cost, i - 2), helper(cost, i - 1)) + cost[i];}
}

分析4

上述代码看起来很简捷,但时间效率非常糟糕。时间效率是面试官非常关心的问题,如果应聘者的解法的时间效率糟糕则很难通过面试。根据前面的递归代码,为了求得f(i)需要先求得f(i-1)和f(i-2)。如果将求解过程用一个树形结构表示(如图14.2中求解f(9)的过程),就能发现在求解过程中有很多重复的节点。例如,求解f(9)需要求解f(8)和f(7),而求解f(8)和f(7)都需要求解f(6),这就意味着在求解f(9)的过程中有重复计算。
求解f(i)这个问题的解,依赖于求解f(i-1)和f(i-2)这两个子问题的解,由于求解f(i-1)和f(i-2)这两个子问题有重叠的部分,如果只是简单地将状态转移方程转换成递归的代码就会带来严重的效率问题,因为重复计算是呈指数级增长的。
为了避免重复计算带来的问题,一个常用的解决办法是将已经求解过的问题的结果保存下来。在每次求解一个问题之前,应先检查该问题的求解结果是否已经存在。如果问题的求解结果已经存在,则不再重复计算,只需要从缓存中读取之前求解的结果。

public class Test {public static void main(String[] args) {int[] cost = {1, 100, 1, 1, 100, 1};int result = minCostClimbingStairs(cost);System.out.println(result);}public static int minCostClimbingStairs(int[] cost) {int len = cost.length;int[] dp = new int[len];helper(cost, len - 1, dp);return Math.min(dp[len - 2], dp[len - 1]);}private static void helper(int[] cost, int i, int[] dp) {if (i < 2) {dp[i] = cost[i];}else if (dp[i] == 0) {helper(cost, i - 2, dp);helper(cost, i - 1, dp);dp[i] = Math.min(dp[i - 2], dp[i - 1]) + cost[i];}}
}

分析5:空间复杂度为O(n)的迭代代码

也可以自下而上地解决这个过程,也就是从子问题入手,根据两个子问题f(i-1)和f(i-2)的解求出f(i)的结果。

public class Test {public static void main(String[] args) {int[] cost = {1, 100, 1, 1, 100, 1};int result = minCostClimbingStairs(cost);System.out.println(result);}public static int minCostClimbingStairs(int[] cost) {int len = cost.length;int[] dp = new int[len];dp[0] = cost[0];dp[1] = cost[1];for (int i = 2; i < len; i++) {dp[i] = Math.min(dp[i - 2], dp[i - 1]) + cost[i];}return Math.min(dp[len - 2], dp[len - 1]);}
}

分析6:空间复杂度为O(1)的迭代代码

上述迭代代码还能做进一步的优化。前面用一个长度为n的数组将所有f(i)的结果都保存下来。求解f(i)时只需要f(i-1)和f(i-2)的结果,从f(0)到f(i-3)的结果其实对求解f(i)并没有任何作用。也就是说,在求每个f(i)的时候,需要保存之前的f(i-1)和f(i-2)的结果,因此只要一个长度为2的数组即可。

public class Test {public static void main(String[] args) {int[] cost = {1, 100, 1, 1, 100, 1};int result = minCostClimbingStairs(cost);System.out.println(result);}public static int minCostClimbingStairs(int[] cost) {int[] dp = new int[] {cost[0], cost[1]};for (int i = 2; i < cost.length; i++) {dp[i % 2] = Math.min(dp[0], dp[1]) + cost[i];}return Math.min(dp[0], dp[1]);}
}

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

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

相关文章

C++ 具名要求-全库范围的概念

此页面中列出的具名要求&#xff0c;是 C 标准的规范性文本中使用的具名要求&#xff0c;用于定义标准库的期待。 某些具名要求在 C20 中正在以概念语言特性进行形式化。在那之前&#xff0c;确保以满足这些要求的模板实参实例化标准库模板是程序员的重担。若不这么做&#xf…

window使用cpolar实现内网穿透

文章目录 cpolar下载和安装启动和配置cpolar卸载 cpolar下载和安装 进入spolar官网&#xff0c;完成注册&#xff0c;下载相应的cploar版本解压和运行安装文件 配置安装路径&#xff0c;然后选择next&#xff0c;完成即可 启动和配置 点击首页的快捷图标打开网页&#xf…

【LeetCode】1158. 市场分析 I

表&#xff1a; Users ------------------------- | Column Name | Type | ------------------------- | user_id | int | | join_date | date | | favorite_brand | varchar | ------------------------- user_id 是此表主键&#xff08;具有唯一值…

Defi安全-Monox攻击事件Foundry复现

其它相关内容可见个人主页 Mono攻击事件的介绍见&#xff1a;Defi安全–Monox攻击事件分析–phalconetherscan 1. 前情提要和思路介绍 Monox使用单边池模型&#xff0c;创建的是代币-vCash交易对&#xff0c;添加流动性时&#xff0c;只需添加代币&#xff0c;即可进行任意代…

Jmeter相关概念

Jmeter相关概念 jmeter性能指标 Aggregate Report 是 JMeter 常用的一个 Listener&#xff0c;中文被翻译为“聚合报告”。今天再次有同行问到这个报告中的各项数据表示什么意思&#xff0c;顺便在这里公布一下&#xff0c;以备大家查阅。 如果大家都是做Web应用的性能测试&a…

八、Vue3组件库经验[Ant Design]

一、Ant Design 地址&#xff1a;https://2x.antdv.com/components/overview-cn/ 1.DatePicker 日期选择框 问题1&#xff1a;当将时间加载到DatePicker 日期选择时&#xff0c;用出现bug卡住&#xff0c;并报错 原因&#xff1a;DatePicker 需要的dayjs处理后的数据格式 …

C语言中关于函数调用的理解

理论 关于函数调用的方式有两类&#xff1a;传值调用和传址调用 传值调用&#xff1a;函数的形参和实参分别占有不同的内存块&#xff0c;对形参的修改不会影响实参。 传址调用&#xff1a;把函数外部创建变量的内存地址传递给函数参数的一种调用方式。可以让函数和函数外面…

每周一算法:倍增法求区间最大最小值(RMQ)

RMQ RMQ 是英文 Range Maximum/Minimum Query 的缩写&#xff0c;表示区间最大&#xff08;最小&#xff09;值。使用倍增思想解决 RMQ 问题的方法是 ST 表&#xff08;Sparse Table&#xff0c; 稀疏表 &#xff09;。ST 表是用于解决 可重复贡献问题 的数据结构。 可重复贡献…

IPv6和IPv4在技术层面的区别

随着互联网的不断发展&#xff0c;IPv4地址资源已经逐渐枯竭&#xff0c;而IPv6地址的使用逐渐成为趋势。IPv6和IPv4作为互联网协议的两个版本&#xff0c;在技术层面存在许多区别。本文将从地址空间、地址表示方法、路由协议、安全性、移动性以及网络性能等方面对IPv6和IPv4进…

Dockerfile的ENV

文章目录 环境总结测试测试1测试2测试3测试4测试5测试6 参考 环境 RHEL 9.3Docker Community 24.0.7 总结 如果懒得看测试的详细信息&#xff0c;可以直接看结果&#xff1a; 一条 ENV 指令可以定义多个环境变量。Dockerfile里可以包含多条 ENV 指令。环境变量的值不需要用…

docker运行状态

systemctl status docker Active: active (running) since 一 2024-01-08 06:21:10 CST; 3min 57s ago [rootlocalhost ~]# systemctl status docker ● docker.service - Docker Application Container EngineLoaded: loaded (/usr/lib/systemd/system/docker.service; enabl…

【MIdjourney】关于图像中人物视角的关键词

本篇仅是我个人在使用过程中的一些经验之谈&#xff0c;不代表一定是对的&#xff0c;如有任何问题欢迎在评论区指正&#xff0c;如有补充也欢迎在评论区留言。 1.全景镜头(panorama) 全景镜头是一种广角镜头&#xff0c;可以捕捉到比普通镜头更广阔的视野范围。全景镜头&…

目标检测-One Stage-YOLOv4

文章目录 前言一、目标检测网络组成二、BoF&#xff08;Bag of Freebies&#xff09;1. 数据增强2.语义分布偏差问题3.损失函数IoUGIoUDIoUCIoU 三、BoS(Bag of Specials)增强感受野注意力机制特征融合激活函数后处理 四、YOLO v4的网络结构和创新点1.缓解过拟合&#xff08;Bo…

Python武器库开发-武器库篇之子域名扫描器开发(四十一)

Python武器库开发-武器库篇之子域名扫描器开发(四十一) 在我们做红队攻防或者渗透测试的过程中&#xff0c;信息收集往往都是第一步的&#xff0c;有人说&#xff1a;渗透的本质就是信息收集&#xff0c;前期好的信息收集很大程度上决定了渗透的质量和攻击面&#xff0c;本文将…

竞赛练一练 第23期:NOC大赛每日一练,python题目刷题第8天,包含答案解析

题目来自:NOC 大赛创客智慧编程赛项Python 复赛模拟题(二) NOC大赛创客智慧编程赛项Python 复赛模拟题(二) 第一题: 编写一个成绩评价系统,当输入语文、数学和英语三门课程成绩时,输出三门课程总成绩及其等级。 (1)程序提示用户输入三个数字,数字分别表示语文、数学、…

Springboot进行多环境配置的2种方式

本文来说下Springboot使用Spring Profile和Maven Profile进行多环境配置 文章目录 概述Spring Profile多环境主配置文件与不同环境的配置文件 Maven ProfileProfile配置资源过滤 Spring Profile与Maven Profile具体使用 概述 原因 在实际的项目上&#xff0c;一般会分三种环境d…

编译原理复习的有用链接

2024年1月7日&#xff0c;考完编译原理&#xff0c;是时候和考试时候的她说再见了&#xff0c;整理一些收藏夹里的链接和思考吧 实验看这里&#xff1a; 编译原理_HNU岳麓山大小姐的博客-CSDN博客 课后习题看这里&#xff1a; 编译原理作业答案github LL1文法复习 [编译原…

Java学习苦旅(二十二)——MapSet

本篇博客将详细讲解Map和Set。 文章目录 搜索概念模型 MapMap.Entry<K, V>Map的常用方法说明TreeMap和HashMap的区别 Set常用方法说明TreeSet和HashSet的区别 结尾 搜索 概念 Map和set是一种专门用来进行搜索的容器或者数据结构&#xff0c;其搜索的效率与其具体的实例…

JSUDO|加速度与阿里云合作云产品

电讯&#xff1a;深圳市加速度软件开发有限公司【加速度jsudo】&#xff0c;与阿里云计算有限公司&#xff08;简称“阿里云”&#xff09;达成合作&#xff0c;双方将在电商、企业管理等应用软件领域就云产品和应用软件更深层次合作。 加速度软件长期以来&#xff0c;一直与阿…

JVM面试系列-01

1. 什么是 JVM&#xff1f; Java程序的跨平台特性主要是指字节码文件可以在任何具有Java虚拟机的计算机或者电子设备上运行&#xff0c;Java虚拟机中的Java解释器负责将字节码文件解释成为特定的机器码进行运行。 因此在运行时&#xff0c;Java源程序需要通过编译器编译成为.…