LeetCode 题解工作台

使用最小花费爬楼梯

给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。 你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。 请你计算并返回达到楼梯顶部的最低花费。 示例 1: 输入: cost = [10, 15 ,2…

category

2

题型

code_blocks

7

代码语言

hub

3

相关题

当前训练重点

简单 · 状态·转移·动态规划

bolt

答案摘要

我们设计一个函数 ,表示从第 个阶梯开始爬楼梯所需要的最小花费。那么答案为 $\min(\textit{dfs}(0), \textit{dfs}(1))$。 函数 的执行过程如下:

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一个整数数组 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
lightbulb

解题思路

方法一:记忆化搜索

我们设计一个函数 dfs(i)\textit{dfs}(i),表示从第 ii 个阶梯开始爬楼梯所需要的最小花费。那么答案为 min(dfs(0),dfs(1))\min(\textit{dfs}(0), \textit{dfs}(1))

函数 dfs(i)\textit{dfs}(i) 的执行过程如下:

  • 如果 ilen(cost)i \ge \textit{len(cost)},表示当前位置已经超过了楼梯顶部,不需要再爬楼梯,返回 00
  • 否则,我们可以选择爬 11 级楼梯,花费为 cost[i]\textit{cost}[i],然后递归调用 dfs(i+1)\textit{dfs}(i + 1);也可以选择爬 22 级楼梯,花费为 cost[i]\textit{cost}[i],然后递归调用 dfs(i+2)\textit{dfs}(i + 2)
  • 返回两种方案中的最小花费。

为了避免重复计算,我们使用记忆化搜索的方法,将已经计算过的结果保存在数组或哈希表中。

时间复杂度 O(n)O(n),空间复杂度 O(n)O(n)。其中 nn 是数组 cost\textit{cost} 的长度。

Python3

class Solution:
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        @cache
        def dfs(i: int) -> int:
            if i >= len(cost):
                return 0
            return cost[i] + min(dfs(i + 1), dfs(i + 2))

        return min(dfs(0), dfs(1))

Java

class Solution {
    private Integer[] f;
    private int[] cost;

    public int minCostClimbingStairs(int[] cost) {
        this.cost = cost;
        f = new Integer[cost.length];
        return Math.min(dfs(0), dfs(1));
    }

    private int dfs(int i) {
        if (i >= cost.length) {
            return 0;
        }
        if (f[i] == null) {
            f[i] = cost[i] + Math.min(dfs(i + 1), dfs(i + 2));
        }
        return f[i];
    }
}

C++

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        int n = cost.size();
        int f[n];
        memset(f, -1, sizeof(f));
        auto dfs = [&](this auto&& dfs, int i) -> int {
            if (i >= n) {
                return 0;
            }
            if (f[i] < 0) {
                f[i] = cost[i] + min(dfs(i + 1), dfs(i + 2));
            }
            return f[i];
        };
        return min(dfs(0), dfs(1));
    }
};

Go

func minCostClimbingStairs(cost []int) int {
	n := len(cost)
	f := make([]int, n)
	for i := range f {
		f[i] = -1
	}
	var dfs func(int) int
	dfs = func(i int) int {
		if i >= n {
			return 0
		}
		if f[i] < 0 {
			f[i] = cost[i] + min(dfs(i+1), dfs(i+2))
		}
		return f[i]
	}
	return min(dfs(0), dfs(1))
}

TypeScript

function minCostClimbingStairs(cost: number[]): number {
    const n = cost.length;
    const f: number[] = Array(n).fill(-1);
    const dfs = (i: number): number => {
        if (i >= n) {
            return 0;
        }
        if (f[i] < 0) {
            f[i] = cost[i] + Math.min(dfs(i + 1), dfs(i + 2));
        }
        return f[i];
    };
    return Math.min(dfs(0), dfs(1));
}

Rust

impl Solution {
    pub fn min_cost_climbing_stairs(cost: Vec<i32>) -> i32 {
        let n = cost.len();
        let mut f = vec![-1; n];

        fn dfs(i: usize, cost: &Vec<i32>, f: &mut Vec<i32>, n: usize) -> i32 {
            if i >= n {
                return 0;
            }
            if f[i] < 0 {
                let next1 = dfs(i + 1, cost, f, n);
                let next2 = dfs(i + 2, cost, f, n);
                f[i] = cost[i] + next1.min(next2);
            }
            f[i]
        }

        dfs(0, &cost, &mut f, n).min(dfs(1, &cost, &mut f, n))
    }
}

JavaScript

function minCostClimbingStairs(cost) {
    const n = cost.length;
    const f = Array(n).fill(-1);
    const dfs = i => {
        if (i >= n) {
            return 0;
        }
        if (f[i] < 0) {
            f[i] = cost[i] + Math.min(dfs(i + 1), dfs(i + 2));
        }
        return f[i];
    };
    return Math.min(dfs(0), dfs(1));
}
speed

复杂度分析

指标
时间complexity is O(n) because we iterate through each step once, and space complexity can be O(n) with the full DP array or optimized to O(1) by storing only the last two states. This trade-off is specific to state transition dynamic programming patterns where only previous states affect the current computation.
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Asks how you handle both starting indices 0 and 1 to ensure minimal cost.

  • question_mark

    Questions about optimizing space while preserving correct state transitions.

  • question_mark

    Wants explanation of why dp[i] = cost[i] + min(dp[i-1], dp[i-2]) captures all possible paths efficiently.

warning

常见陷阱

外企场景
  • error

    Confusing array indices and overstepping boundaries when computing dp[i].

  • error

    Failing to account for starting from index 1, which may yield a lower total cost.

  • error

    Attempting to reconstruct the path instead of just computing minimum cost, which can overcomplicate the solution.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Climbing stairs with variable maximum step size per stair.

  • arrow_right_alt

    Min cost climbing stairs with constraints on consecutive step selections.

  • arrow_right_alt

    Counting the number of distinct minimum-cost paths to reach the top.

help

常见问题

外企场景

使用最小花费爬楼梯题解:状态·转移·动态规划 | LeetCode #746 简单