字节跳动算法题

1,179 阅读3分钟

有一只青蛙跳一次可以上一个台阶,也可以上两个台阶,最多能上三个台阶。 问跳上 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]
}

(完)