爬楼梯的几种解法
第三天的打卡,今天没有上网课,下次上网课大概是明天吧。
题目描述
假设你正在爬楼梯。需要 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 阶
题目原链接https://leetcode-cn.com/problems/climbing-stairs/
解题思路描述
最简单的方法就是只考虑最后一个台阶的走法,当没有台阶,返回0,还有一层台阶,返回1,即剩一个台阶时只有一种方法,离终点有两层台阶时,有两种可能,1+1或2(一次迈两个台阶或者一次迈一个台阶,走两步),所以返回2。这样就设置好了递归的出口,其他需要我们做的就是进行递归了,把一次迈两个台阶和一次迈一个台阶的方法数加起来。思路整理如下:
- 设置递归出口,没有台阶,剩一个台阶和剩两个台阶的方法数写出来。
- 调用自身 f(n-1)+ f(n-2)走一步的方法数和走两步的方法数之和。
代码如下
class Solution {
public:
int climbStairs(int n) {
if(n == 0) return 0;//当只剩最后一层楼梯时没有办法选择,因此是0种方案
if(n == 1) return 1;
if(n == 2) return 2;
return climbStairs(n-1) + climbStairs(n-2);
}
};
但递归中进行循环次数过多,导致计算结果超过了时间限制。
这种方法是代码最简洁的,但是却超出了时间限制,并且时间复杂度过于高,可以达到O(2∧n)。
下图为官方给出的n=5时的递归树。
针对递归法的改良
针对暴力破解即递归法,可以进行的改良是写一个大小为n+1的数组,数组内存放运算所得的值即【0,1,2,3,。。。。。】(数组的索引是台阶数,而值则是程序运算所得的解法),这样在递归的时候,如果可以从数组中找到值的步骤就直接返回值,再不断把运算过程中产生的结果(数组中暂时没有的值)存放到数组中,以备下次计算,可以减少迭代的次数,同时增加运算速度。
解题的第二种方法
我认为是把递归转化为循环,这样可以把时间复杂度由原来的O(2∧n)减小到O(n)。因为只需要一个for语句。思路和递归的思路类似。递归是只考虑最后一步,即只想结果不想过程。循环的话就从第一个台阶开始思考。只有一个台阶的话,是一种方法,两个台阶,是两种方法。推理一下,三个台阶,第一次迈一个台阶,方法数就是走两个台阶的方法数,第一次迈两个台阶,就是走一个台阶的方法数,以此类推。简单描述如下:
- 用函数表示爬楼梯,则参数n表示楼梯数,f(n)表示一共的方法数。
- 经过前面的思考,可以知道f(1)= 1 ,f(2)= 2,f(3)= f(1)+ f(2)。
- 推理可得f(4)= f(3)+ f(2),f(5)= f(4)+ f(3),f(n)= f(n-1)+ f(n-2)
- 带入循环中,可以从 f(3) 求解到f(n)。
代码如下
class Solution {
public:
int climbStairs(int n) {
int* res = new int[n+1];
if( n == 1 ) return 1;
res[1] = 1 ;
res[2] = 2 ;
if( n > 2 ){
for(int i = 3 ; i <= n ; i ++){
res[i] = res[i-1] + res[i-2];
}
}
return res[n];
}
};
提交结果如下
执行用时是很快的,在毫秒级以内。
今日打卡结束,生命不止,学习不休。
女人皆祸水,美妙仅两回,或是坠爱河,或是临终前-----《卡门》