You are climbing a staircase. It takes n steps to reach the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
Example 1:
Input: n = 2
Output: 2
Explanation: There are two ways to climb to the top.
- 1 step + 1 step
- 2 steps
Example 2:
Input: n = 3
Output: 3
Explanation: There are three ways to climb to the top.
- 1 step + 1 step + 1 step
- 1 step + 2 steps
- 2 steps + 1 step
Constraints:
1 <= n <= 45
法一:暴力递归自顶向下(超时)
倒推一下,假设当前位于第 n 阶,那么爬上本级台阶前可能在n-1级台阶,也可能在n-2级台阶。
所以f(n) = f(n-1) + f(n-2)
递归边界: 式子中最小为 n-2 ,根据题意 n-2 >= 0(也可以严格大于0,区别不大,后面相应修改) ,那么 n >= 2。意味着最后一次递归调用为 f(2) = f(1) + f(0),边界就是 f(1) = 1,f(0) = 1。
class Solution {
public:
int climbStairs(int n) {
if (n == 0 || n == 1)
return 1;
return climbStairs(n - 1) + climbStairs(n - 2);
}
};
法二:备忘录版递归自顶向下
利用备忘录解决重叠子问题
class Solution {
public:
int getAns(vector<int> &vec, int n)
{
if (n == 0 || n == 1)
return 1;
if (vec[n] != 0)
return vec[n];
vec[n] = getAns(vec, n - 1) + getAns(vec, n - 2);
return vec[n];
}
int climbStairs(int n) {
vector<int> vec(n + 1, 0);
vec[0] = vec[1] = 1;
return getAns(vec, n);
}
};
动态规划自底向上
f(x) 表示爬到第 x 级台阶的方案数,考虑最后一步可能跨了一级台阶,也可能跨了两级台阶,所以我们可以列出如下式子:
f(x) = f(x - 1) + f(x - 2)
很好理解,因为每次只能爬 1 级或 2 级,所以 f(x) 只能从 f(x - 1) 和 f(x - 2) 转移过来,而这里要统计方案总数,我们就需要对这两项的贡献求和。
class Solution {
public:
int climbStairs(int n) {
if (n == 1)
return 1;
if (n == 2)
return 2;
vector<int> dp(n + 1, 0);
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n; i++)
dp[i] = dp[i - 1] + dp[i - 2];
return dp[n];
}
};
优化空间复杂度版:
class Solution {
public:
int climbStairs(int n) {
if (n == 1)
return 1;
if (n == 2)
return 2;
int pre = 1, cur = 2;
for (int i = 3; i <= n; i++)
{
int rec = pre + cur;
pre = cur;
cur = rec;
}
return cur;
}
};