小鑫的算法之路:leetcode0070 爬楼梯

题目

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

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

提示:

1 <= n <= 45

解法1:记忆化搜索

假如需要到达第n阶楼梯时,可以在n-1阶时爬1阶,或者n-2阶爬2阶到达。那么递推公式很容易得到,即f(n) = f(n - 1) + f(n - 2);

递归终止条件有两个,一个是n = 1时,f(1) = 1,因为只有一种方式到第一个台阶,另外一个是n = 2时,f(2) = 2,因为有两种方式到第二个台阶。

但是,很容易发现在该递归处理中有很多重复子问题,时间复杂度会达到O(2^n),时间复杂度极高。为了避免相同子问题的重复计算,需要对子问题的答案进行保存。在每次求解时,先判断是否存在该子问题答案,如果存在则直接使用,否则对子问题进行求解处理。

代码如下:

class Solution {
public:
    int climbStairs(int n) {
        if (result_[n] == 0) {
            result_[n] = climbStairs(n - 1) + climbStairs(n - 2);
        }

        return result_[n];
    }

private:
    // 由于当前题目的台阶范围为[1, 45], 因此初始化长度为46的数组, 除开索引为1和2的初始值分别为1和2外,其余值均为0
    array<int, 46> result_ = {{0, 1, 2}};
};

时间复杂度为O(n),空间复杂度为O(1),因为以46固定长度分配数组空间。执行结果如下:

在这里插入图片描述

解法2:动态规划

记忆化搜素属于自上而下的问题解决方式,本题也可使用自下而上的动态规划方式先对各个子问题求解, 最终得到问题的答案。

代码如下:

class Solution {
public:
    int climbStairs(int n) {
        // 由于当前题目的台阶范围为[1, 45], 因此初始化长度为46的数组, 除开索引为1和2的初始值分别为1和2外,其余值均为0
        array<int, 46> result = {{0, 1, 2}};  

        for (int i = 3; i <= n; ++i) {
            result[i] = result[i - 1] + result[i - 2];
        }

        return result[n];
    }
};

时间复杂度为O(n),空间复杂度为O(1),固定长度分配。执行结果如下:

在这里插入图片描述

解法3:内存优化后的动态规划

在解法2中,固定分配了长度为46的数组,但是针对本题,无需保存那么多子问题的解,通过递推公式发现只需保存前两个子问题的解即可。代码如下:

class Solution {
public:
    int climbStairs(int n) {
        if (n == 1) {
            return 1;
        }

        if (n == 2) {
            return 2;
        }

        int pre_result = 2;
        int pre_two_result = 1;
        int result = 0;
        for (int i = 3; i <= n; ++i) {
            result = pre_result + pre_two_result;
            pre_two_result = pre_result;  // 先更新前两次子问题的结果
            pre_result = result;  // 再更新前一次子问题的结果
        }

        return result;
    }
};

时间复杂度为O(n),空间复杂度为O(1)。执行结果如下:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值