首发于掘金
原文链接
转载请写明掘金链接
前言 🎤
闲来无事想到折腾点没用的。
普通递归法
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
}
时空比较
| 类型 | 时间 | 空间 |
|---|---|---|
| reduce | 0.250ms | 9.734KB |
| nomarl | 0.072ms | 1.757KB |
| nomarl-one-space | 0.096ms | 14.367KB |
| nomarl-one-space-real | 0.049m | 0.484KB |
| recursion | 75267.654ms | 14584.625KB |
| recursion-plus | 0.140ms | 14.265KB |
| generator | 0.200ms | 21.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`)
});