フィボナッチ数列を理解する
n番目の数値は、シーケンスの最初の2つの合計です:f(n)= f(n-1)+ f(n -2)、コードを使用してフィボナッチ数列を実装することは、再帰的な書き込みを調査することに他なりません。彼は無数の役に立たない計算を行ったため、再帰のみを使用することは、時間の複雑さと空間の複雑さの厳密な要件では実行できません。
1、1、2、3、5、8、13、…
通常の実装(再帰的)
このように計算すると、繰り返し計算が多くなり、再帰層の数がどんどん深くなり、スタックを再帰的にバーストしやすくなります。
const fib = n => n <= 1 ? n :fib(n-1)+fib(n-2)
console.log(fib(5))
時間の複雑さを軽減します(閉鎖+再帰)
キャッシュのレイヤーを追加することで、以前に計算された値を保存するために使用されます。新しい値を計算する必要がある場合は、最初にキャッシュが検索され、キャッシュヒットが直接返され、計算が行われます。見逃した場合は続行します。ただし、配列を使用すると、スペースが複雑になります。
const fib3 = function (n) {
n <= 1 && n
const cache = []
cache[0] = 1
cache[1] = 1
function memoize(num) {
if (cache[num] !== undefined) {
return cache[num]
}
cache[num] = memoize(num - 1) + memoize(num - 2)
// console.log(cache[num])
return cache[num]
}
const result = memoize(n-1)
return result
}
console.log(fib3(4))
ただし、この実装には問題があります。フィボナッチ数列を順番に計算しないと、追加の消費量が増加します。たとえば、fib(1000)を直接計算します。このとき、中央にある他の配列項目は次のようになります。未定義に初期化されます。これは小さくなります。しばらくの間ですが、計算が完了すると、1から1000までのフィボナッチ数列が埋められます。
参照ネットワークの1つの解決策は、配列をキャッシュ用のオブジェクトに置き換えることです。これにより、未定義を埋める時間が短縮されます。
// 闭包 + 缓存对象
const fibonacci = (function () {
const f = {
}
return function(n) {
if(n === 0 || n === 1) {
return n
}
if(f[n-2] === undefined) {
f[n-2] = fibonacci(n-2)
}
if(f[n-1] === undefined) {
f[n-1] = fibonacci(n-1)
}
return f[n] = f[n-1] + f[n-2]
}
})()
書き方を前から後ろに変更するには:::前のカウントから段階的に、段階的に計算し、nまで計算します
const fib =function (n){
n <= 1 && n
const cache = []
cache[0] = 1
cache[1] = 1
for (let i= 2; i<=n; i++ ) {
cache[i] = cache[i-1] +cache[i-2]
}
return cache[n-1]
}
console.log(fib(5))
スペースの複雑さを軽減
と配列を使用しないでください、前から後ろにスペースの寸法を減らしてください
const fib = n =>{
n <= 1 && n
let prev2 = 0
let prev1 = 1
let result = 0
for (let i = 2;i<=n;i++) {
result =prev2+prev1
prev2 = prev1
prev1 = result
}
return result
}