70.爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 :
输入: 3
输出: 3
解法一:递归
很明显是一个递归的题目,我们可以很轻松地写出这样的代码。
我们知道,当还剩0级时,方法为0,
还剩1级时,方法为1,即1个台阶直接上去。
还剩2级时,方法为2,一次2个台阶或者两次1个台阶。
因此若n<=2直接返回n。
int climbStairs(int n)
{
if(n<=2) return n;
return climbStairs(n-1)+climbStairs(n-2);
}
但是这样产生了大量重复计算,很容易就超时了,因此需要寻找效率更高的算法。
时间复杂度为O(2^n)
解法二:循环求和
分析上面的代码,可以知道这就是一个斐波那契数列,第三项的值等于前两项之和,因此我们可以直接按照斐波那契数列求和。
class Solution {
public:
int climbStairs(int n)
{
if(n<=2) return n;
int p=1,q=2,ans=0;
for(int i=2;i<n;++i)
{
ans=p+q;
p=q;
q=ans;
}
return ans;
}
};
这样就可以通过测试。
但是我转念一想,不太对,我做这道题是为了学习动态规划呢,前面好像都不是,还得有另一种解法。
解法三:动态规划(自底向上)
这种方法和解法二大致相同,但是采用了动态规划的思想,即将小规模的问题答案储存起来,最后用于大规模问题的解答。
int climbStairs(int n) {
int* dp = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
for (int i=3; i<=n; i++)
{
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
解法四:动态规划(带备忘录的自顶向下)
int climb_Stairs(int i, int n, int dp[]) {
if (i > n) {
return 0;
}
if (i == n) {
return 1;
}
if (dp[i] > 0) {
return dp[i];
}
dp[i] = climb_Stairs(i + 1, n, dp) + climb_Stairs(i + 2, n, dp);
return dp[i];
}
int climbStairs(int n) {
int *dp = new int[n + 1];
return climb_Stairs(0, n, dp);
}
解法五:套公式
在看别人的解法的时候发现了一个更奇妙的方法,时间复杂度也更低,运用了斐波那契数列的直接计算公式
- 时间复杂度为O(logn)
class Solution {
public:
int climbStairs(int n) {
double sqrt_5 = sqrt(5);
double ans=pow((1 + sqrt_5) / 2, n +1) -pow((1 - sqrt_5) / 2,n+1);
return (int)(ans/ sqrt_5);
}
};
方法任选一种即可