【leetcode】70.爬楼梯js

题目

思路

第一秒想到是递归,且看到n最大是45觉得应该够,然后也这么写了。

javascript 复制代码
/**
 * @param {number} n
 * @return {number}
 */
var climbStairs = function(n) {
    if (n === 1) return 1
    if (n === 2) return 2
    return climbStairs(n-1) + climbStairs(n-2)
};

于是喜提超时。

老老实实写动态规划了。

代码

动态规划

代码随想录动规五部曲:

1.确定dp数组(dp table)以及下标的含义

dpi:爬到第i阶楼梯有dpi种方法

2.确定递推公式

可以倒着想,爬上第n阶台阶的话有两种方式,一种是从第n-1阶爬一阶上来,一种是从第n-2阶爬两阶上来。而第n-1阶和第n-2阶有多少种方式又分为两种往前推,所以显而易见的:dpn = dpn-1+dpn-2

3.dp数组如何初始化

题目说n是正整数,所以从1开始看就可以了。

n=1,dp1=1:一步

n=2,dp2=2:两步/两个一步

4.确定遍历顺序

从递推公式可知一定是从前往后遍历的。

5.举例推导dp数组

例如n=4时,dp数组应为:

n=1,dp1=1

n=2,dp2=2

n=3,dp3=dp1+dp2=3

n=4,dp4=dp2+dp3=5

javascript 复制代码
/**
 * @param {number} n
 * @return {number}
 */
var climbStairs = function(n) {
    if (n <= 2) return n
    const dp=[]
    dp[1] = 1
    dp[2] = 2
    for (let i = 3; i <= n; i++){
        dp[i] = dp[i-1] + dp[i-2]
    }
    return dp[n]
};

递归(记忆版)

但如果我硬要用递归呢()

其实我觉得本质上还是动态规划,只是写法比较"递归"。这种写法是考虑到递归要重复计算很多次,那我直接把算过的存起来不就好了。这还是跟动态规划一个思想,只不过动规是自底向上,而记忆版递归是自顶向下。

javascript 复制代码
/**
 * @param {number} n
 * @return {number}
 */
var climbStairs = function(n) {
    const memory = {}// 用来存算过的值
    function dfs(n) {
        if (n === 1) return 1
        if (n === 2) return 2
        
        // 算过的直接返回
        if (memory[n] !== undefined) return memory[n]
        // 没算过的加进去
        memory[n] = dfs(n-1) + dfs(n-2)

        return memory[n]
    }
    return dfs(n) 
};