我们用 f(x)f(x)f(x) 表示爬到第 xxx 级台阶的方案数,考虑最后一步可能跨了一级台阶,也可能跨了两级台阶,所以我们可以列出如下式子:
f(x)=f(x−1)+f(x−2)
它意味着爬到第xxx 级台阶的方案数是爬到第 x−1x - 1x−1 级台阶的方案数和爬到第 x−2x - 2x−2 级台阶的方案数的和。很好理解,因为每次只能爬 111 级或 222 级,所以 f(x)f(x)f(x) 只能从 f(x−1)f(x - 1)f(x−1) 和 f(x−2)f(x - 2)f(x−2) 转移过来,而这里要统计方案总数,我们就需要对这两项的贡献求和。
作者:力扣官方题解 链接:leetcode.cn/problems/cl… 来源:力扣(LeetCode)
爬楼梯
-
先读题
数学函数思维总共2种走法(走一阶或二阶) f(n)n阶台阶有多少种走法?利用函数思想:
f(n-1)
f(n-2)
f(n) = f(n-1) + f(n-2)
递归 并不是一种算法,而是一种实现的方式
代码的执行是一个栈数据结构,存在函数栈的入栈,内存会被不断使用,达到临界值:
比如f(10) 执行了函数 ,推入执行栈
(let a = 1;) 内存里开辟了一个数值型的内存空间,并把1值 放进去了
//递归
//自顶向下
//每个问题都相同
//退出条件
var climbStairs = function(n) {
if(n===1)return 1;
if(n===2)return 2;
return climbStairs(n-1) + climbStairs(n-2);
};
// 结果瞬间占满整个函数栈
上面代码会给我们带来一些疑惑:
1.递归带来的内存问题怎么办?
2.递归的优点是什么?简单,但是性能不好
3.如果不往执行栈里push太多层函数,是不是就不会占满函数栈?
因此入栈过的函数是没必要再入栈的
当n=100时,是没有对应f[n]的值的, 函数就会一直执行f[n]=climbStairs(n-1)+ climbStairs(n-2)递到f[3],发现f[3]=climbStairs(3-1) + climbStairs(3-2)可以得到值并记录f[3]的值,再重新计算f[4]、f[5]...归到f[100]
//第二种做法 记忆法
const f = [];//全局
const climbStairs=function(n){
//退出条件
if(n===1)return 1;//递归终止条件
if(n===2)return 2;
if(f[n]===undefined){ //第一次
//函数嵌套函数
f[n]=climbStairs(n-1) + climbStairs(n-2);//递归公式
}
return f[n];
}
不用递归还能怎么做?
其实还可以利用for循环,可以简化代码
把const f= []放到函数体内可以直接调用
//自底向上 递推 dp 动态规划
const climbStairs=function(n){
const f= [];//优化
f[1]=1
f[2]=2
for(let i=3;i<=n;i++){
f[i]=f[i-1]+f[i-2]
}
return f[n]
}
以上三种方法可以参考,如果还有哪些更好的方法可以留言。