每次爬1级或2级台阶
递推公式: f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n)=f(n-1)+f(n-2) f(n)=f(n−1)+f(n−2)
递推公式解释:爬n级台阶 = 爬n-1级台阶,再爬一级台阶+爬n-2级台阶,再爬2级台阶
但如果直接这样写,
class Solution {
public:
int climbStairs(int n) {
if(n==1)
return 1;
if(n==2)
return 2;
return climbStairs(n-1)+climbStairs(n-2);
}
};
但是这种方法时间复杂度很高,力扣超时了,为什么?
我们来看他的递归树,以当n=5为例:
我们会发现,这棵递归树中我们出现了好几次n=1,n=2和n=3,说明我们重复计算了,而这种重复计算会随着n的增加变得越来越多。
为了避免这种重复计算,我们这里用一个容器来保存已经计算过的值,这种方法叫做记忆性递归
在函数外声明一个unordered_map,用来存储计算过的值
class Solution {
public:
unordered_map<int,int> mp;
int climbStairs(int n) {
if(n==1)
return 1;
if(n==2)
return 2;
//查找是否已经计算过,使用find方法查找,返回的是一个迭代器
auto ret = mp.find(n);
//如果迭代器不等于mp.enr(),说明已经计算过
if(ret!=mp.end())
return ret->second; //直接返回,注意这里不是mp[ret]
//如果没有计算过
int sum = climbStairs(n-1)+climbStairs(n-2);
mp[n]=sum;
return sum;
}
};
动态规划
上述是用递归法来计算,我们也可以用动态规划解决这个问题,用dp[n]表示爬到第n阶台阶时的方法,采用迭代来获取最终结果
class Solution {
public:
int climbStairs(int n) {
if(n==1)
return 1;
vector<int> vec(n+1);
vec[1] = 1;
vec[2] = 2;
for(int i=3;i<=n;i++){
vec[i]=vec[i-1]+vec[i-2];
}
return vec[n];
}
};