题目描述
原题链接: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数组:
(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];
}
};