JS中7种方法实现斐波那契数列(不包括公式法)

1,862 阅读2分钟

首发于掘金
原文链接
转载请写明掘金链接

前言 🎤

闲来无事想到折腾点没用的。

普通递归法

function (n) { // N,N
    if (n < 2) return n
    return arguments.callee(n - 1) + arguments.callee(n - 2)
}

尾递归优化法

function fibonacci(n, current, next) {
    if(n === 1) return next;
    if(n === 0) return 0;
    return fibonacci(n - 1, next, current + next);
}

动态规划法

(n) => { // 动态规划 N,1
    let dp = [0, 1]
    for (let i = 2; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2]
    }
    return dp[n]
}

动态规划,表面空间复杂度O(1)法

(n) => { // 动态规划缩减版 表面 N,1
    let [prev, cur] = [0, 1]
    while (n-- > 0) [prev, cur] = [cur, prev + cur]
    return prev
}

动态规划,真实空间复杂度O(1)法

(n) => { // 真实动态规划缩减版 N,1 
    let prev = 0,cur = 1
    let t = 0
    while (n-- > 0){
        t = prev
        prev = cur
        cur = t + cur
    }
    return prev
}

Array.reduce实现

(n) => { // N,1
    return new Array(n).fill(0).reduce(prev => [prev[1], prev[0] + prev[1]], [0, 1])[0]
}

生成器法

(n)=>{ // 一个没啥意义的版本 N,1
    let g = (function* (){
        let [cur,last] = [0,1]
        yield cur;
        yield last;
        while(true){
            yield (cur + last);
            [cur,last] = [last,cur + last]
        }
    })()

    let result = 0
    while(n-->= 0) result = g.next().value
    return result
}

时空比较

类型时间空间
reduce0.250ms9.734KB
nomarl0.072ms1.757KB
nomarl-one-space0.096ms14.367KB
nomarl-one-space-real0.049m0.484KB
recursion75267.654ms14584.625KB
recursion-plus0.140ms14.265KB
generator0.200ms21.0546KB

总结 👨‍🏫

Generator不应该在这种场景使用,有点对不住他。

附带测试版本

"use strict";
let tree = {
    'reduce': (n) => { // N,1
        return new Array(n).fill(0).reduce(prev => [prev[1], prev[0] + prev[1]], [0, 1])[0]
    },
    'nomarl': (n) => { // 动态规划 N,1
        let dp = [0, 1]
        for (let i = 2; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2]
        }
        return dp[n]
    },
    'nomarl-one-space': (n) => { // 动态规划缩减版 表面 N,1
        let [prev, cur] = [0, 1]
        while (n-- > 0) [prev, cur] = [cur, prev + cur]
        return prev
    },
    'nomarl-one-space-real': (n) => { // 真实动态规划缩减版 N,1 
        let prev = 0,cur = 1
        let t = 0
        while (n-- > 0){
            t = prev
            prev = cur
            cur = t + cur
        }
        return prev
    },
    'recursion': function (n) { // N,N
        if (n < 2) return n
        return arguments.callee(n - 1) + arguments.callee(n - 2) // arrow have not arguments
    },
    'generator':(n)=>{ // 一个没啥意义的版本 N,1
        let g = (function* (){
            let [cur,last] = [0,1]
            yield cur;
            yield last;
            while(true){
                yield (cur + last);
                [cur,last] = [last,cur + last]
            }
        })()

        let result = 0
        while(n-->= 0) result = g.next().value
        return result
    },
    'recursion-plus':function fibonacci(n, current, next) {
        if(n === 1) return next;
        if(n === 0) return 0;
        return fibonacci(n - 1, next, current + next);
    }
    
}

Object.keys(tree).forEach(name => {
    console.time(name)
    let mem = process.memoryUsage()
    let fib = tree[name]
    function no(n) {
        throw new Error(`${n} but ${fib(n)}`)
    }
    try {
        fib(0) == 0 || no(0)
        fib(1) == 1 || no(1)
        fib(2) == 1 || no(2)
        fib(10) == 55 || no(10)
        fib(45) == 1134903170 || no(45)
    } catch (e) {
        console.log(`err:${name} when ${e.message}`)
    }
    let nowMem = process.memoryUsage()
    console.timeEnd(name)
    
    console.log(`${name} mem:${(nowMem.heapUsed - mem.heapUsed)/1024}KB`)
});