LeetCode:爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 12.  2

示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 12.  1 阶 + 23.  2 阶 + 1

方法一 —— 记忆化递归

由于递归太耗时,可以用记忆化递归避免重复的计算。
解题过程:
1.先对n为0这种特殊情况进行处理,然后n为1和2时直接return即可
2.memo数组:存储中间结果,避免重复计算
3.接下来就是判断memo[n]是否存在,如果计算过即存在,直接返回,无需重复计算;若不存在,则进行递归计算,为前两个之和。
代码

/**
 * @param {number} n
 * @return {number}
 */
const memo = []
var climbStairs = function(n) {
    
    
    if( n === 0) return 1
    if(n <= 3) return n
    if(memo[n]) {
    
    
        return memo[n]
    }else {
    
    
        memo[n] = climbStairs(n-1) + climbStairs(n-2)
    }
    return memo[n]
}

方法二 —— 动态规划(常规)

解题过程:
1.如果只有0阶或者1阶,则直接返回n。(后面直接从2阶及以上开始,防止0/1阶导致数组出现空指针)
2.dp[i]:爬到i层楼梯,有dp[i]种方法
3.从i=3开始遍历,因为必须要有前两个存在,且存在dp[n] = dp[n-1] + dp[n-2]的关系。
代码

/**
 * @param {number} n
 * @return {number}
 */
var climbStairs = function(n) {
    
    
    if (n <= 1) return n

    const dp = new Array(n)
    dp[1] = 1
    dp[2] = 2
    for (let i = 3; i <= n; i++) {
    
    
        dp[i] = dp[i-1] + dp[i-2]
    }
    return dp[n]
}

方法三 —— 动态规划(滚动数组思想 ==> 优化空间为O(1))

解题过程:
1.先定义好三个常量,利用向左移动的思想,使得计算过程中只使用了常数个变量,且存在r = p + q的关系
2.只用常数个变量作为辅助空间,故渐进空间复杂度为 O(1)
代码

/**
 * @param {number} n
 * @return {number}
 */
var climbStairs = function(n) {
    
    
    let p = 0, q = 0, r = 1  
    for (let i = 1; i<= n; i++) {
    
    
        p = q
        q = r
        r = p + q
    }
    return r
};

方法四 —— 动态规划(非数组法)

目前所有的动态规划都有这两种写法:用数组或非数组。不用数组的也可以理解成滑动窗口、双指针。
解题过程:
1.当有0、1、2个台阶时,分别有0、1、2种方法,用return直接返回
2.prev用于记录前一个台阶,初始值为第一个台阶,curr用于记录当前台阶,初始值为第二个台阶
3.然后从第三个台阶开始循环,执行到第n个台阶。
代码

var climbStairs = function(n) {
    
    
    if(n <= 2) {
    
    
        return n
    }
    let prev = 1
    let curr = 2
    for(let i = 3;i <= n; i++) {
    
    
        let temp = prev + curr
        prev = curr
        curr = temp
    }
    return curr
}

猜你喜欢

转载自blog.csdn.net/Bertil/article/details/120694999