题目链接: 爬楼梯官方题解下方的评论区
爬楼梯解答
有关题目
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。且不能连续跳两个台阶
你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
题解
法一:动态规划
思路:
定义:f(x) 表示爬到第 x 级台阶的方案数
g(x, 1) 表示爬到第 x 级台阶并且最后一步跨越一个台阶的方案数
g(x, 2) 表示爬到第 x 级台阶并且最后一步跨越了两个台阶的方案数
则有: f(x) = g(x, 1)+g(x,2), g(x, 1) = f(x-1), g(x, 2) = g(x-2, 1)
// 最后一步跨越了两步,那么上一步只能跨越一步
最终得到一下方程式: f(x) = g(x, 1) + g(x, 2) = f(x-1)+g(x-2, 1) = ( g(x-1, 1)+g(x-1, 2) )+g(x-2, 1) = g(x-1, 1)+g(x-1, 2)+g(x-2, 1)
代码一:
int climbStairs(int n){
int dp[n + 1][3];
dp[1][1] = 1, dp[2][1] = 1, dp[2][2] = 1;
for (int i = 3; i <= n; i++){
dp[i][1] = dp[i - 1][2] + dp[i - 1][1];
dp[i][2] = dp[i - 2][1];
}
return dp[n][1] + dp[n][2];
}
代码二:
int climbStairs2(int n){
// one[i] 最后一次是爬 1 层楼梯到达楼梯 i
// two[i] 最后一次是爬 2 层楼梯到达楼梯 i 的方法数
int one[n + 1], two[n + 1];
one[0] = 1, two[0] = 1;
one[1] = 1, two[1] = 0;
for (int i = 2; i <= n; i++){
one[i] = one[i - 1] + two[i - 1];
two[i] = one[i - 2];
}
return one[n] + two[n];
}
时间复杂度:O(n)
空间复杂度:O(n)
法二:动态规划优化
思路1:
结合执行树会更快理解:
6
/ \
5 4
/ \ /
4 3 3
/ \ / / \
3 2 2 2 1
/ \ / / \ / \ /
2 1 1 1 0 1 0 0
/ \ / / / /
1 0 0 0 0 0
/
0
其中左节点为权 1,右节点为权 2,很明显,问题的解为树的非空叶节点个数。
思路二:
假设:
f(x) 表示爬到第 x 级台阶的方案数,
g(x, 1) 表示爬到第 x 级台阶并且最后一步跨越一个台阶的方案数,
g(x, 2) 表示爬到第 x 级台阶并且最后一步跨越了两个台阶的方案数。
由 :
f(x) = g(x, 1)+g(x,2),
g(x, 1) = f(x-1),
g(x, 2) = g(x-2, 1) // 最后一步跨越了两步,那么上一步只能跨越一步
f(x) = g(x, 1) + g(x, 2)
= f(x-1) + g(x-2, 1)
= f(x-1) + f((x-2)-1)
= f(x-1) + f(x-3)
代码片段:
int climbStairs(int n){
int dp[n + 1];
dp[0] = 1;
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n ; i++){
dp[i] = dp[i - 1] + dp[i - 3];
}
return dp[n];
}
时间复杂度:O(n)
空间复杂度:O(n)
法三:滚动数组
1 1 2 3 4
1 2 3
int climbStairs(int n){
if (n <= 2) return n;
int pppre = 1, ppre = 1, pre = 2;//012
int ans = 0;
for (int i = 3; i <= n; i++){
ans = pppre + pre;
pppre = ppre;
ppre = pre;
pre = ans;
}
return ans;
}
时间复杂度:O(n)
空间复杂度:O(1)