首页 > 其他分享 >剑指offer88:爬楼梯的最少成本

剑指offer88:爬楼梯的最少成本

时间:2022-12-13 11:32:43浏览次数:42  
标签:爬楼梯 offer88 min int len 最少 台阶 dp cost


题目:

数组的每个下标作为一个阶梯,第 i 个阶梯对应着一个非负数的体力花费值 cost[i](下标从 0 开始)。

每当爬上一个阶梯都要花费对应的体力值,一旦支付了相应的体力值,就可以选择向上爬一个阶梯或者爬两个阶梯。

请找出达到楼层顶部的最低花费。在开始时,你可以选择从下标为 0 或 1 的元素作为初始阶梯。

1.

输入:cost = [10, 15, 20]

输出:15

解释:最低花费是从 cost[1] 开始,然后走两步即可到阶梯顶,一共花费 15 。

2.

输入:cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]

输出:6

解释:最低花费方式是从 cost[0] 开始,逐个经过那些 1 ,跳过 cost[3] ,一共花费 6 。

分析:

该题每次爬的时候既可以往上爬1级台阶也可以爬两级台阶,也就是说每一步都有两个选择。看似这与回溯法有关,但这个问题不是要找出有多少种方法可以爬上楼梯,而是要计算爬上楼梯的最少成本,即计算问题的最优解,因此这个问题更适合动态规划。

针对动态规划方法,首先我们就要确定状态转移方程,可以用f(i)表示从楼梯的第i级台阶再往上爬的最少成本。如果一个楼梯有n级台阶(台阶从0级一直到第n-1级),由于一次可以爬1级或2级台阶,因此可以从第n-2级台阶或第n-1级台阶爬到楼梯的顶部,即f(n-1)和f(n-2)的最小值就是这个问题的最优解。从第i级台阶往上爬的最少成本应该是从第i-1级台阶往上爬的最少成本和从第i-2级台阶往上爬的最少成本的较小值再加上第爬第i级台阶的成本=》f(i)=min(f(i-1),f(i-2))+cos[i]。该方程有个隐含条件,即i大于等于2,如果i等于0,则可以直接从第0级台阶往上爬。f(0)=cos[0],如果i等于1,题目中提到可以从第1级台阶出发往上爬,因此f(1)=cos[1]。

该题有四种解法:

圈9代表f(9),第一种解法代码看似简单,但是时间复杂度十分糟糕,例如f(6)需要计算很多次,其实只要计算一次就够了,其他的计算都是多余的,所以我们需要剪枝操作来,也就是第二种解法,避免重复计算,利用数组来存储结果。

或者我们可以换一种思路从下而上来解决这个过程,也就是从子问题入手,根据两个子问题f(i-1)和f(i-2)的解求出f(i)的结果。第四种思路是在第三种思路的基础上优化,主要是为了降低空间复杂度,前面利用了一个长度为n的数组将所有f(i)的结果都保存下来,求解f(i)的结果都保存下来。但求解f(i)时只需要f(i-1)和f(i-2)的的结果,从0到f(i-3)的结果其实对求解f(i)没有任何作用,因此只需要一个长度为2的数组就可以了,具体看代码。

剑指offer88:爬楼梯的最少成本_数组

代码:

import java.util.Map;

public class MinCostClimbingStairs {
public static void main(String[] args) {
MinCostClimbingStairs minCostClimbingStairs = new MinCostClimbingStairs();
int[] cost = {1,100,1,1,100,1};
int i = minCostClimbingStairs.minCostClimbingStairs3(cost);
System.out.println(i);
}
public int minCostClimbingStairs(int[] cost){
int len = cost.length;
return Math.min(helper1(cost,len-2),helper1(cost,len-1));
}

private int helper1(int[] cost, int i) {
if (i<2){
return cost[i];
}
return Math.min(helper1(cost,i-1),helper1(cost,i-2))+cost[i];
}
//利用数组来存储结果
public int minCostClimbingStairs1(int[] cost) {
int len = cost.length;、
//该数组的每个元素都初始化为0
int[] dp = new int[len];
helper(cost,len-1,dp);
return Math.min(dp[len - 2],dp[len - 1]);
}

private void helper(int[] cost, int i, int[] dp) {
if (i < 2){
dp[i] = cost[i];
//由于每级台阶往上爬的成本都是正数,因此如果某个问题f(i)之前已经求解过了,那么一定是一个大于0的数值。
}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];
}
}
// 自下而上,这个思路感觉要比自上而下的思路更好想
public int minCostClimbingStairs2(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-1],dp[i-2])+cost[i];
}
return Math.min(dp[len-2],dp[len-1]);
}
//优化空间复杂度解法
public int minCostClimbingStairs3(int[] cost){
int[] dp = new int[]{cost[0],cost[1]};
for (int i = 2; i < cost.length; i++) {
// 用f(i)的结果覆盖f(i-2)的结果并不会带来任何问题
// dp[0] 从开始到最终分别对应的是下标为0 2 4 6...的数组值,dp[1]同理。
// 求解的f(i)的结果保存在数组下标为“i%2”的位置。
dp[i%2] = Math.min(dp[0],dp[1]) + cost[i];
}
return Math.min(dp[0],dp[1]);
}
}

剑指offer88:爬楼梯的最少成本_Math_02


标签:爬楼梯,offer88,min,int,len,最少,台阶,dp,cost
From: https://blog.51cto.com/u_15911055/5933499

相关文章

  • 1827. 最少操作使数组递增
    1827.最少操作使数组递增classSolution{publicintminOperations(int[]nums){intn=nums.length;intres=0;for(inti=1;i......
  • 1827. 最少操作使数组递增 ----- 贪心算法
    给你一个整数数组 nums (下标从0开始)。每一次操作中,你可以选择数组中一个元素,并将它增加 1 。比方说,如果 nums=[1,2,3] ,你可以选择增加 nums[1] 得到 nums=......
  • 力扣每日一题2022.12.11---1827. 最少操作使数组递增
    给你一个整数数组 nums (下标从0开始)。每一次操作中,你可以选择数组中一个元素,并将它增加 1 。   比方说,如果 nums=[1,2,3] ,你可以选择增加 nums[1] 得到 n......
  • 力扣---70. 爬楼梯
    假设你正在爬楼梯。需要n 阶你才能到达楼顶。每次你可以爬1或2个台阶。你有多少种不同的方法可以爬到楼顶呢?示例1:输入:n=2输出:2解释:有两种方法可以爬到楼顶。1.1......
  • leetcode_D7_70爬楼梯
    1.题目  2.解一  主要思路:自己的想法,内存和时间占用好像都不少。i为爬一个台阶的的个数,j为爬两个台阶的个数,通过循环计算出所有满足i*1+j*2==n的i和j,再对i和j......
  • [研究中] 固定半径最少圆覆盖问题/固定数量最小半径覆盖问题
    一、固定半径最少圆覆盖问题背景:二维坐标轴中,给出n个点以及每个点的坐标(坐标为浮点型),和一个长度m(m为浮点型),求至少需要多个半径为m的圆可以把所有点覆盖住输入:第一行输入n......
  • 力扣 leetcode 1775. 通过最少操作次数使数组的和相等
    问题描述给你两个长度可能不等的整数数组nums1和nums2。两个数组中的所有值都在1到6之间(包含1和6)。每次操作中,你可以选择任意数组中的任意一个整数,将它变成......
  • 通过最少操作次数使数组的和相等
    题目给你两个长度可能不等的整数数组 nums1和 nums2 。两个数组中的所有值都在 1 到 6 之间(包含 1 和 6)。每次操作中,你可以选择任意 数组中的任意一个整数,......
  • 用最少的代码打造一个Mini版的gRPC框架
    在《用最少的代码模拟gRPC四种消息交换模式》中,我使用很简单的代码模拟了gRPC四种消息交换模式(Unary、ClientStreaming、ServerStreaming和DuplexStreaming),现在我们更近......
  • 区间列表的交集 和相同的二元子数组 生成交替二进制字符串的最少操作数
    986.区间列表的交集List<int[]>list=newArrayList<>();intn=firstList.length;intm=secondList.length;inti=0;intj=0;while(i<n&&j<m){交......