假设你正在爬楼梯。需要 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 步
这是一个很经典的问题了,记得高中的数学课上就讲过这个问题。这个问题如果按照正常的逻辑来思考,从第一层爬到顶有多少种方式,那就太复杂了,不符合我们算法求解的要求。
既然从第一层向上推导太复杂,那我们可以换一个思路:那就是从顶层往回退。假如我们要爬n层楼梯,还剩一层就到顶了,那么我们再向上走一步就能到顶,如果设爬上n-1层楼梯的方式有f(n-1)种,那么在这种情况下,我们爬上第n层也有f(n-1)种方式。
但是,还没有结束,因为最后一步可以爬1层也可以爬2层,那么我们爬上最后一层可以是从n-2层一次爬了2层到第n层。这种情况下,爬n层楼梯又有了f(n-2)中方式。
由于每次只能上1层或者2层楼梯,所以到达第n层的最后一步就只能是从n-1层爬1层,从n-2层爬两层。那么爬上n层楼梯的总方式就为f(n)=f(n-1)+f(n-2)。有没有很熟悉这个公式啊,对,这就是著名的斐波那契数列啊
既然是熟悉的斐波那契数列,那就不多说了吧,直接上代码:
public int climbStairs(int n) { if (n == 0) { return 0; } if (n == 1) { return 1; } if (n == 2) { return 2; } return climbStairs(n - 1) + climbStairs(n - 2); }
这是最简单的斐波那契数列的写法,使用了递归,但是这种写法的时间复杂度太大。
提交结果:
于是又经过思考,耗时太长的原因是使用了递归,能不能不用递归来实现呢?
public int climbStairs(int n) { if (n <= 1) { return 1; } int res = 0; int n1 = 1; int n2 = 1; for (int i = 2; i <= n; ++i) { res = n2 + n1; n1 = n2; n2 = res; } return res; }
这次改进之后好多了