青蛙跳台阶问题主要考察的是动态规划,想要深入了解动态规划,就要先了解入门问题,而青蛙跳台阶问题是最典型的案例
题目要求
n个台阶,青蛙一次可以跳一节,也可以一次跳两节,问有多少种跳法可以跳到顶部。
这个问题我们自己思考似乎就很难解决。但是拆分成一个个小的问题,然后找这些小问题之间的关联,就能够清晰解决。
递归函数方法
我们可以这样思考,我们可以先认为跳上n级台阶一共有两种情况,第一种情况,最后一步跳两节,第二种情况,最后一步跳一节,如图:
这个时候无论前面是什么情况,不用管前面的,只管最后一步,就只有两种情况,
我们可以用一个函数fn(n)来表示青蛙跳跳一节和跳两节的数量
fn(n)=最后一步跳两节的数量 + 最后一步跳一节的数量
我们这时可以思考一下,最后一步跳一节的数量是不是等于前面n-1节台阶跳跃的所有情况的数量,同理最后一步跳两节节的数量是不是等于前面n-2节台阶跳跃的所有情况的数量
那么就是 fn(n)= fn(n-1)+fn(n-2)
这个跳台阶思路清楚了,编写代码就比较容易了,代码如下:
<script>
//递归方法
function fn(n) {
if (n <= 0) { //需要考虑台阶的数量,当等于0时,跳台阶的方法也为零
return 0
}
if (n <= 2) { //当台阶数量小于等于2时,跳台阶的方法就等于台阶本身数量
return n
}
return fn(n - 2) + fn(n - 1) //大于2时正常执行业务,跳台阶方法数量就等于n-2节台阶时跳台阶的方法数量+n-1节台阶时跳台阶的方法数量
}
</script>
采用递归方法虽然简便,但是执行效率不太好,最好使用循环。任何递归都可以写成循环 任何循环也可以写成递归,它们之间是互通的。
循环函数方法
采用循环写法,需要定义两个变量,我们用 one 来表示跳一节的数量,用two来表示跳两节的数量
这时我们思考一下,如果跳第三节台阶,那和我们只跳一节台阶的方法数量和只挑两节台阶的方法数量有什么关联呢?
刚刚我们已经得出:最后一步跳一节的数量是不是等于前面n-1节台阶跳跃的所有情况的数量,同理最后一步跳两节节的数量是不是等于前面n-2节台阶跳跃的所有情况的数量
那么跳第三节台阶的方法数量就等于 前面one 跳一节的数量 + two跳两节的数量
代码如下:
<script>
// 循环方法
function fn1(n) {
if (n <= 0) { //先考虑两种特殊情况
return 0
}
if (n <= 2) {
return n
}
let one = 1,
two = 2 //定义两个变量 one 来表示跳一节的数量,用two来表示跳两节的数量
for (let i = 3; i <= n; i++) { //从第三个台阶开始做循环
let temp = two //定义一个临时变量来存储最后一步跳两节的数量
two = one + two
one = temp
}
return two
}
</script>
循环流程图大概如下图:我们可以看到最后n节台阶时的方法数量为 two,输出即可
对递归函数和循环函数进行调用
可以得出正确的结果:
<script>
console.log(fn1(1));
console.log(fn1(2));
console.log(fn1(3));
console.log(fn1(4));
console.log(fn1(10));
console.log(fn(1));
console.log(fn(2));
console.log(fn(3));
console.log(fn(4));
console.log(fn(10));
</script>
注意,当n数量过于大时递归函数执行效率非常缓慢,造成程序运行时间过长,可能会有卡死现象,不信你可以试试。