每日一题,防止痴呆 = =
一、题目大意
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/climbing-stairs
二、题目思路以及AC代码
今天的每日一题是两年前做过的一道题 = =,也是一道比较经典的DP吧,下面我按照官解给出的多个思路的目的,一个个的说一下
思路一:动态规划
这个肯定是可以用动态规划求解的。我们令dp[i]表示爬i层台阶共有多少种方法,那么我们又知道每次只能爬1或2个台阶,那么dp[i] = dp[i-1] + dp[i-2],直接用DP解决即可,时间复杂度是O(n),然后我们发现其实这个DP只用到了三个数,所以空间复杂度就可以由O(n)优化到O(1)。
思路二:矩阵快速幂
我们发现,由上面提到的矩阵的递推公式可以得到以下公式:
也就是说,我知道了f(0)和f(1)之后,我们可以通过不断的乘一个固定的矩阵来得到想要的f(n),那其实就是一个求矩阵幂的问题,关于幂运算,我们是有快速幂的方法可以使得复杂度是O(logn)的,当然矩阵的乘法复杂度是O(1),然后空间复杂度也是O(1)。
思路三:直接用通项公式求解
这就是数学问题了,其实我们观察递推公式就可以发现,这个DP数组其实就是一个斐波那契数列,那么我们就可以直接求通项公式,然后将n带入求解,但这里面会涉及到浮点数精度的问题,而且由于通项公式中含有幂次,所以时间复杂度还是O(logn),空间复杂度是O(1)。
AC代码
这里只将思路一中的DP写一下,其实也就是在求斐波那契数列而已。
class Solution {
public:
int climbStairs(int n) {
if (n < 2) return 1;
int first = 1;
int second = 1;
int third;
for (int i=2;i<=n;i++) {
third = first + second;
first = second;
second = third;
}
return third;
}
};
如果有问题,欢迎大家指正!!!