假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2 输出: 2 解释: 有两种方法可以爬到楼顶。 1. 1 阶 + 1 阶 2. 2 阶
示例 2:
输入: 3 输出: 3 解释: 有三种方法可以爬到楼顶。 1. 1 阶 + 1 阶 + 1 阶 2. 1 阶 + 2 阶 3. 2 阶 + 1 阶
这个问题恰好在阿里电话面试的时候被问到,本渣确实很渣,而且leetcode没有怎么刷哈哈哈哈哈,就比较惨。
听到这个题我隐隐觉得不妙,本渣不怎么会动态规划,抱着必死的决心听完题目。
首先的想法是,这个题比较类似给你1元2元5元10元...让你凑100元有多少种凑法。我就说了“暴力破解”,然后讲了一下大致思路。小哥哥说“这个复杂度是不是有点高”。我说“emmm,是的”。经过本渣实验,这个不仅仅是复杂度的问题,在某种层面上讲,这个题目不是很适合用暴力,因为会考虑不周,将“先走一步,再走两步”和“先走两步,再走一步”这种类似情况判为同一种方案。
//暴力破解考虑不到1.2;2.1的情况
class Solution {
public:
int climbStairs(int n)
{
int count=0;
for(int i=0;i<=n;i++)
{
for(int j=0;j<=(n/2);j++)
{
if((i+(j*2))==n)
count++;
}
}
return count;
}
};
而后,本渣给小哥哥说,我们不然可以直接套用排列组合的公式,直接计算出对应的结果。事实证明,后面还有一种公式方法证明野蛮生长才是最好的方法。
小哥哥说是一种方案,而后,本渣求助了一下度老师,看到了递归,动态规划基本就是靠递归。我说“递归比较费空间”,小哥哥说“空间不要紧了,现在这么发达了”。咳咳,空间还是要紧的,不信,下面的代码就超出运行时间限制了。然后小哥哥引导我“斐波那契数列”,我了解啊,生兔子的故事,度老师递归那里也讲了,S(N)=S(N-1)+S(N-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);
}
};
在实验过程中,决定采用迭代的方案依托“斐波那契”进行求解。获得了胜利,主体思路还是生兔子哈哈哈哈哈哈。
//AC代码迭代法
class Solution {
public:
int climbStairs(int n)
{
int nums=0;
int one=1,two=2;
if(n==1)
return 1;
if(n==2)
return 2;
for(int i=3;i<=n;i++)
{
nums=one+two;
one=two;
two=nums;
}
return nums;
}
};
最后,一种也蛮生长的方案:“斐波那契数列”通项公式,就是涉及0.618和1.618的那个表达式。这个大佬的BLOG里面有写,代码直接用的大佬的了。其实讲道理,我最喜欢这个大佬的方式,太直接了。哈哈哈。
https://blog.youkuaiyun.com/u010412858/article/details/79790176
class Solution {
public:
int climbStairs(int n)
{
n++;
double root5 = sqrt(5);
double result = 1 / root5*(pow((1 + root5) / 2, n) - pow((1 - root5) / 2, n));
return (int)(result);
}
};