题目链接:https://leetcode.com/problems/climbing-stairs/
1. 题目介绍(Climbing Stairs)
You are climbing a staircase. It takes n steps to reach the top.
【Translate】: 你正在爬楼梯,爬到山顶要走n步。
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
【Translate】: 每次你可以爬1或2级台阶,你可以用多少种不同的方式爬到顶?
【测试用例】:
【条件约束】:
2. 题解
爬上n阶台阶有两种情况:从第n-1阶台阶往上爬,或者是从n-2阶台阶网上爬。那么爬上n-1阶台阶也有两种情况:从n-2阶台阶往上爬1个台阶,或者是从n-3阶台阶往上再爬2阶。以此类推。
因此我们可以写出递推公式,f(n)
是爬上n阶台阶的方法数。
2.1 纯递归
原题解来自于maxlivinci的Java from Recursion to DP。题解代码如下:
/**
* Recustion (Top Down Approach) 自顶向下
* Question : Climbing Stairs
* Complexity : Time: O(2^n) ; Space: O(n)
*/
class Solution {
public int climbStairs(int n) {
if (n == 0) {
return 0;
}
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
return climbStairs(n - 1) + climbStairs(n - 2);
}
}
该方法属于完全按照递推公式进行,不进行其它任何操作,简单易懂,但时间复杂度过大,无法通过AC。
2.2 递归 + Map (记忆化搜索)
本质上还是递归的思想,但由于递归解法重复的计算,我们可以把之前计算过的数值保存到Map键值对中,这样可以有效避免重复。
/**
* Recustion + Memorization (Top Down Approach)
* Question : Climbing Stairs
* Complexity : Time: O(n) ; Space: O(n)
*/
class Solution {
public int climbStairs(int n) {
Map<Integer, Integer> memo = new HashMap<>();
memo.put(1, 1);
memo.put(2, 2);
return climbStairs(n, memo);
}
private int climbStairs(int n, Map<Integer, Integer> memo) {
if (memo.containsKey(n)) {
return memo.get(n);
}
memo.put(n, climbStairs(n - 1, memo) + climbStairs(n - 2, memo));
return memo.get(n);
}
}
2.3 动态规划
动态规划法在求解子问题时,会保存该子问题的解,后面的子问题求解时,可以直接拿来计算,这无疑是要比递归的效率高上很多。
/**
* DP (Bottom Up Approach)
* Question : Climbing Stairs
* Complexity : Time: O(n) ; Space: O(n)
*/
class Solution {
public int climbStairs(int n) {
if (n <= 1) {
return 1;
}
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}
2.4 动态规划 + 最优化
为了计算新的值,我们只利用前两个值。因此,我们不需要使用数组来存储之前的所有值。
/**
* DP + Optimization (Bottom Up Approach)
* Question : Climbing Stairs
* Complexity : Time: O(n) ; Space: O(1)
*/
class Solution {
public int climbStairs(int n) {
if (n <= 1) {
return 1;
}
int prev1 = 1;
int prev2 = 2;
for (int i = 3; i <= n; i++) {
int newValue = prev1 + prev2;
prev1 = prev2;
prev2 = newValue;
}
return prev2;
}
}
3. 参考资料
[1] 70. Climbing Stairs | CSDN
[2] 五大基础算法–动态规划法 | 华为云