LeetCode:使用最小花费爬楼梯

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、解题思路

1. 定义 DP 数组
  • dp[i] 表示 爬到第 i 阶楼梯的最小花费

  • 由于可以选择从 0 或 1 开始,初始化:

    • dp[0] = cost[0](从第 0 阶开始的花费)

    • dp[1] = cost[1](从第 1 阶开始的花费)

2. 状态转移方程
  • 对于 i >= 2,爬到第 i 阶的最小花费 = 当前阶的花费 cost[i] + 从 i-1 或 i-2 爬上来的最小花费

dp[i] = cost[i] + Math.min(dp[i-1], dp[i-2]);

3. 最终结果
  • 由于最后一步可以直接从 n-1 或 n-2 跨到顶部,所以最终结果是:

return Math.min(dp[cost.length - 2], dp[cost.length - 1]);

public int minCostClimbingStairs(int[] cost) {
        int[] dp = new int[cost.length+1];
       dp[0] = cost[0];//1
       dp[1] = cost[1];//100
        for (int i = 2; i < cost.length; i++) {
            dp[i] = cost[i] + Math.min(dp[i-1], dp[i-2]); //爬到第 i 阶的最小花费 = 当前阶的花费 cost[i] + 从 i-1 或 i-2 爬上来的最小花费
        }
        return Math.min(dp[cost.length - 2], dp[cost.length - 1]);//由于最后一步可以直接从 n-1 或 n-2 跨到顶部,所以最终结果是返回两者之间最小值

    }

优化空间:不使用数组的 DP 实现

上面的代码使用了 O(n) 空间存储 dp 数组,但我们可以优化成 O(1) 空间,因为 dp[i] 只依赖 dp[i-1] 和 dp[i-2]

优化思路
  • 用 3 个变量 代替 dp 数组:

    • prev1 表示 dp[i-2](前两阶的最小花费)

    • prev2 表示 dp[i-1](前一阶的最小花费)

    • current 表示 dp[i](当前阶的最小花费)

public int minCostClimbingStairs(int[] cost) {
    int n = cost.length;
    int prev1 = cost[0]; // dp[0]
    int prev2 = cost[1]; // dp[1]
    
    for (int i = 2; i < n; i++) {
        int current = cost[i] + Math.min(prev1, prev2);
        prev1 = prev2;   // 更新 prev1 为前一阶的值
        prev2 = current; // 更新 prev2 为当前阶的值
    }
    
    return Math.min(prev1, prev2); // 最后一步可以从 n-2 或 n-1 跨到顶部
}

复杂度分析
  • 时间复杂度O(n),遍历一次 cost 数组。

  • 空间复杂度O(1),仅用 3 个变量存储状态。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值