【LeetCode】No.70. Climbing Stairs -- Java Version

81 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情.

题目链接:leetcode.com/problems/cl…

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级台阶,你可以用多少种不同的方式爬到顶?

【测试用例】:

testcase

【条件约束】:

Constraint

2. 题解

climbing stairs 爬上n阶台阶有两种情况:从第n-1阶台阶往上爬,或者是从n-2阶台阶网上爬。那么爬上n-1阶台阶也有两种情况:从n-2阶台阶往上爬1个台阶,或者是从n-3阶台阶往上再爬2阶。以此类推。

因此我们可以写出递推公式,f(n)是爬上n阶台阶的方法数。 strict test

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。 act1

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);
    }
}

act2

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];
    }
}

act3

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;
    }
}

act4

3. 参考资料

[1] 70. Climbing Stairs | CSDN

[2] 五大基础算法--动态规划法 | 华为云