動態規劃 Dynamic programming
using ‘Cache’ Memoization
動態規劃的基本思想是將「原始問題」分解成多個「子問題」,先求解並「儲存」這些子問題的解到 cache,然後通過這些子問題的解來提供給原問題。這樣做的目的是避免重複計算,從而提高算法的效率。
Dynamic Programming = Divide-and-Conquer + Memoization (Cache) 與 分而治之 Divide-and-Conquer 很像,但最大的差別是子問題大多類似,並先儲存子問題的解到 cache,之後需要使用到時就不用重複計算
基本概念 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 let cache = {}; function memoizeAddTo80 (n ) { if (n in cache) { return cache[n]; } else { console .log ("first time run" ); const answer = n + 80 ; cache[n] = answer; return answer; } } console .log (memoizeAddTo80 (6 ));console .log (memoizeAddTo80 (6 ));
Closure 使用 Closure 讓 cache 可以存於 local scope 中,不外洩。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function memoizeAddTo80 ( ) { let cache = {}; return function (n ) { if (n in cache) { return cache[n]; } else { console .log ("first time run" ); const answer = n + 80 ; cache[n] = answer; return answer; } }; } const memoized = memoizeAddTo80 ();const memoized2 = memoizeAddTo80 (); console .log (memoized (6 ));console .log (memoized (6 ));console .log (memoized2 (6 ));console .log (memoized2 (6 ));
常見運用 Counter 1 2 3 4 5 6 7 8 9 10 11 12 13 const createCounter = function (n ) { let count = n; return () => count++; }; const counter = createCounter (10 );counter (); counter (); counter (); const counter2 = createCounter (5 );counter2 (); counter2 ();
最經典的例子 費波那契數列 Fibonacci numbers 前面 recursion 有提到的解法 為 O(2^n) 再加上 cache 可讓解法變成 O(n)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 function fibonacciRecursive (n ) { if (n < 2 ) { return n; } return fibonacciRecursive (n - 2 ) + fibonacciRecursive (n - 1 ); } console .log (fibonacciRecursive (6 )); function fibonacciIterative (n ) { let fibonacciArr = [0 , 1 ]; for (i = 2 ; i <= n; i++) { fibonacciArr[i] = fibonacciArr[i - 1 ] + fibonacciArr[i - 2 ]; } return fibonacciArr[n]; } console .log (fibonacciIterative (6 ));
Dynamic programming 解法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function fibonacciRecursive ( ) { const cache = {}; return function fib (n ) { if (n in cache) { return cache[n]; } else { if (n < 2 ) { return n; } else { cache[n] = fib (n - 2 ) + fib (n - 1 ); return cache[n]; } } }; } const DPfib = fibonacciRecursive ();console .log (DPfib (6 ));
學習與參考資料