有一只青蛙跳一次可以上一个台阶,也可以上两个台阶,最多能上三个台阶。 问跳上 n 阶台阶有多少种跳法。
解法一
我们可以让 n 等于 1,2,3,4分别看一下怎么求解
当n等于1的时候只有一种跳法,即直接从起点跳上第一阶台阶。所以 f(1) = 1。
当n等于2的时候有两种跳法分别是,直接从起点跳上第二阶台阶,和先跳到第一阶再从第一阶台阶跳到第二阶台阶。 所以 f(2) = 1 + f(1)*1 = 2
当n等于3的时候一共有三种方法分别是,直接从起点跳上第三阶台阶,从第一阶台阶跳到第三阶台阶f(1),和从第二阶台阶跳到第三阶台阶f(2)。 所以 f(3) = 1 + f(1)*1 + f(2)*1 = 1+1+2 = 4
当n等于4的时候一共有三种方法分别是,从第一阶台阶跳到第四阶台阶f(1),和从第二阶台阶跳到第四阶台阶f(2),和从第三阶台阶跳上第四阶台阶f(3)。 所以 f(4) = f(1)*1 + f(2)*1 + f(3)*1 = 1 + 2 + 4 = 7
当n等于5的时候一共有三种方法分别是,从第二阶台阶跳到第五阶台阶f(2),和从第三阶台阶跳到第五阶台阶f(3),和从第四阶台阶跳上第五阶台阶f(4)。 所以 f(5) = f(2)*1 + f(3)*1 + f(4)*1
看我们得到了规律了
前三个阶梯的跳法的和总等于下一个阶梯的跳法
所以我们可以写出如下迭代:
function f(x) {
// 定义三种跳法 fa, fb, fc 并分别附上初始值 1,2,4。
let fa = 1,
fb = 2,
fc = 4;
// 当要求的阶梯数小于等于三的时候直接给出答案。
if(x === 1){
return fa;
}
if(x === 2){
return fb;
}
if(x === 3){
return fc;
}
// 当阶梯数大于等于4时,通过前面的数据逐步推算出跳上下一阶台阶的跳法。
let result = 0;
for(let i = 4; i <= x; i++){
// 跳上下一阶台阶的跳法等于 一次跳三阶 + 一次跳两阶 + 一次跳一阶
result = fa + fb +fc;
// 跳上去以后距离下次台阶的距离+1所以,我们要做相应的调整使得fa,fb,fc,距离下一个台阶分别是相差 1 阶,相差 2阶, 和相差 3 阶。
fa = fb;
fb = fc;
fc = result;
}
// 返回结果
return result;
}
题目也就迎刃而解了。
解法二
分析问题,阶梯有n层,最后小青蛙是一定要到达的,但是小青蛙一次性只能跳1,2,3阶阶梯中的一种。 所以我们知道青蛙一定是从 n-1层 n-2 层和 n-3层跳上来的。即 f(n) = f(n-1) + f(n-2) + f(n-3),这样我们就把一个大问题分解成了三个子问题,尽管我们没办法直接得出答案,但是我们确实让这个问题变得简单了,因为求f(n-1)比求f(n)要简单,只要 n 足够小我们就能直接得出答案,比如 f(1) = 1,f(2) = 2,f(3) = 4, 所以利用我们发现的规律我们可以使得 f(n-1) = f(n-2) + f(n-3) + f(n-4), 来继续让n变小,直到 n<=3, 很容易让我们想到递归。
function f(x) {
if(x === 3){
return 4;
}
if(x === 2){
return 2;
}
if(x === 1){
return 1;
}
return f(x - 1) + f(x - 2) + f(x - 3);
}
由于递归带来的性能问题我们可以用尾递归,或者迭代来优化。
function f(x, a = 1, b = 2, c = 4) {
if(x === 3) {
return c;
}
if(x === 2) {
return b;
}
if(x === 1) {
return a;
}
return f(x - 1, b, c, a + b + c);
}
解法三
动态规划
function f(x){
dp = [1,2,4]
if(x<=3){
return dp[x-1]
}
for(let i = 3; i<x; i++){
dp[i] = dp[i-1]+dp[i-2]+dp[i-3]
}
return dp[x-1]
}
(完)