总结
easy题。
题目形成的数列正好是斐波那契数列,答案要求的f(n)f(n)f(n)即是斐波拉契数列的第n项(下标从0开始),本题可按照求解斐波拉契第n项的求解方法。
- n 比较小的时候,可以直接使用过递归法求解,不做任何记忆化操作,时间复杂度是O(2n)O(2^n)O(2n),存在很多冗余计算。
- 一般情况下,使用「记忆化搜索」或者「迭代」的方法,实现这个转移方程,时间复杂度和空间复杂度都可以做到O(n)O(n)O(n)。
- 为了优化空间复杂度,可以不用保存 f(x−2)f(x−2)f(x−2) 之前的项,只用三个变量来维护 f(x)、f(x−1)f(x)、f(x−1)f(x)、f(x−1) 和 f(x−2)f(x−2)f(x−2),可以理解成是把「滚动数组思想」应用在了动态规划中,也可以理解成是一种递推,这样把空间复杂度优化到了O(1)O(1)O(1)。
- 随着 n 的不断增大 O(n)O(n)O(n) 可能已经不能满足我们的需要了,我们可以用「矩阵快速幂」的方法把算法加速到O(logn)O(logn)O(logn)。
- 也可以把 n 代入斐波那契数列的通项公式计算结果,但是如果我们用浮点数计算来实现,可能会产生精度误差。
假设你正在爬楼梯。需要 n
阶你才能到达楼顶。
每次你可以爬 1
或 2
个台阶。你有多少种不同的方法可以爬到楼顶呢?
说明:给定n是一个正整数。
示例1:
输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例2:
输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
提示:
1 <= n <= 45
进阶:
题目分析:
- 第1级台阶:1种方法(爬1级)
- 第2级台阶:2种方法(爬1级或爬两级)
- 第3级台阶:3种方法(第1级+第2级)
- 第n级台阶:从第n-1级台阶爬1级或从第n-2级台阶爬2级
——递推公式:Fn=Fn−1+Fn−2F_n=F_{n-1}+F_{n-2}Fn=Fn−1+Fn−2
class Solution {
public:int climbStairs(int n) {if(n==1)return 1;if(n==2)return 2;else return climbStairs(n-1)+climbStairs(n-2);}
};
减少时间复杂度,避免重复计算
用meno[]数组来记忆每次计算的结果,存储中间结果
class Solution {
public:int climbStairs(int n) {//存储中间结果,避免重复计算int *memo=new int[n+1];return climbStairsMemo(n,memo);}int climbStairsMemo(int n,int memo[]){//判断爬到n级方法是否计算过,若计算过直接返回memo[n]的值if(memo[n]>0){return memo[n];}if(n==1){memo[n]=1;}else if(n==2){memo[n]=2;}else{memo[n]=climbStairsMemo(n-1,memo)+climbStairsMemo(n-2,memo);}return memo[n];}
};
爬到每一级的方法看作一个状态,用dp[]数组记录状态,从1-n依次更新每个状态。
虽然在动态规划算法中记录了全部n个状态,但只有两个状态在更新下一个状态的时候才被用到;若只记录这两个状态,就可以将空间复杂度从O(n)O(n)O(n)优化到O(1)O(1)O(1)。
class Solution {
public:int climbStairs(int n) {if(n==1){return 1;} //dp[]记录n个状态int *dp=new int[n+1];dp[1]=1;dp[2]=2;//从1-n依次更新for(int i=3;i<=n;i++){dp[i]=dp[i-1]+dp[i-2];}return dp[n]; }
};
将爬楼梯问题转换成斐波拉契数列问题。
用滚动数组记录n-1和n-2两个状态
每次状态更新之后,先把状态2移动到状态1的位置,再把状态3移动到状态2的位置,把状态整体向前滚动一位,
class Solution {
public:int climbStairs(int n) {if(n==1){return 1;} int first=1;int second=2;for(int i=3;i<=n;i++){int third=first+second;//滚动数组first=second;second=third;}return second; }
} ;