145、【动态规划】leetcode ——70. 爬楼梯:暴力法+动态规划(C++/Python版本)

题目描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
原题链接:70. 爬楼梯

解题思路

1、暴力法

递归方式

class Solution {
public:
    int res = 0;
    void traversal(int n) {
        if(n == 0) {			// 每遍历出一种情况,就将结果加一
            res++;
            return ;
        }   
        else if (n < 0) {
            return ;
        }
        climbStairs(n - 1);		// 探寻当以一步移动的情况
        climbStairs(n - 2);     // 探寻当以两步移动的情况
    }
    int climbStairs(int n) {
        traversal(n);
        return res;
    }
};

此方式会超时。

2、动态规划

因为楼梯只有上一步和上两步,所以到达第i阶楼梯,可以根据到达由第i - 1阶楼梯到达,或由第i - 2阶楼梯到达。也就是说到达第i阶楼梯的方法个数,可以依托于到达第i - 1阶楼梯的方法个数,或依托于到达第i - 2阶楼梯的方法个数。

递归法五部曲:
(1)dp[i]的含义: 到达第i阶楼梯的方法个数
(2)递推公式: dp[i] = dp[i - 1] + dp[i -2]
(3)dp数组初始化: dp[0] = 0,dp[1] = 1, dp[2] = 2
(4)遍历顺序: 递归从后往前,迭代从前往后
(5)举例推导dp数组:
image.png

(1)递归法

也相当于是后序遍历

class Solution {
public:
    int dp[46];
    int climbStairs(int n) {
        if(n == 0)          return 1;
        else if(n < 0)      return 0;
        if(dp[n] != 0)      return dp[n];
        dp[n] = climbStairs(n - 1) + climbStairs(n - 2);
        
        return dp[n];
    }
};

(2)迭代法

class Solution {
public:
    int climbStairs(int n) {
        if(n <= 1)          return n;
        int dp[46] = {0, 1, 2};
        for(int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
};

Python

n = int(input())

if n <= 2:
    print(n)
else:
    dp = [0] * (n + 1)
    dp[0], dp[1], dp[2] = 0, 1, 2

    for i in range(3, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]

    print(dp[n])

两个变量优化
仅设置两个变量来记录,dp1始终指向最后一个数,dp0指向其前一个数。

class Solution {
public:
    int climbStairs(int n) {
        if(n <= 1)          return n;        
        int sum = 0, dp0 = 1, dp1 = 2;
        for(int i = 3; i <= n; i++) {
            sum = dp0 + dp1;
            dp0 = dp1;
            dp1 = sum;
        }
        return r;
    }
};

(3)完全背包思路

  • 动态规划五步曲:

(1)dp[j]含义: 楼梯层数为j的前提下,以一步或两步向上走,走到底j层共有几种走法。

(2)递推公式: dp[j] += dp[j - i],完全背包的递推公式

(3)dp数组初始化: dp[0] = 1,在第0层时只有一种方式,这样子设置便于后续计算。

(4)遍历顺序: 因为为排列问题,同一个数不同位置代表不同含义,因此是先遍历背包,再遍历物品,滚动数组从小到大。

(5)举例: (省略)

class Solution {
public:
    int climbStairs(int n) {
        int dp[46] = {0};
        dp[0] = 1;

        for(int j = 1; j <= n; j++) {
            for(int i = 1; i <= 2; i++) {
                if(j >= i)      dp[j] += dp[j - i];
            }
        }

        return dp[n];
    }
};

参考文章:70. 爬楼梯

二维数组

class Solution {
public:
    int climbStairs(int n) {
        vector<vector<int>> dp(2 + 1, vector<int>(n + 1));
        for(int i = 0; i <= 2; i++)         dp[i][0] = 1;

        for(int j = 0; j <= n; j++) {
            for(int i = 1; i <= 2; i++) {
            	// 把0-i的情况都再探查一遍
                for(int k = i; k > 0; k--) {
                    if(j >= k) {                        
                        dp[i][j] += dp[i][j - k];
                    } 
                }
            }
        }


        return dp[2][n];
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

辰阳星宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值