algorithms-dyanmic-programming.md
๐ก๋์ ํ๋ก๊ทธ๋๋ฐ Dynamic Programming๐ (with fibonacci)
๐ ์บ์ฑ์ ์ฌ์ฉํ๋ ์ต์ ํ ๊ธฐ๋ฒ
- ์ต์ ํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐ
- ์ค๋ณต๋ ์ฐ์ฐ์ ํผํ๊ธฐ ์ํด ์ฌ์ฉ
- ์์ ํ์ ๋ฌธ์ ๋ค์ ํด๊ฒฐ์ฑ ์ ์กฐํฉ โ ์ ์ฒด ๋ฌธ์ ๋ฅผ ํด๊ฒฐ
๐ ์ฃผ๋ก ์ฌ์ฉ๋๋ ์์
- ํผ๋ณด๋์น ์์ด
- Longest Common Substring (์ต์ฅ ๊ณตํต ๋ถ๋ถ ๋ฌธ์์ด)
- 0/1 Knapsack Problem (0/1 ๋ฐฐ๋ญ ๋ฌธ์ )
- ๊ทธ๋ํ์ ์ต๋จ ๊ฒฝ๋ก
๐ ์ถ๊ฐ ๋ฌธ์
- House Robber
- Best Time to Buy and Sell Stock
- Climbing Stairs
CodeSandbox : ์ฝ๋ ์๋๋ฐ์ค ์์ ํ์ด์ง
๋์ (๋ค์ด๋๋ฏน) ํ๋ก๊ทธ๋๋ฐ์ด๋?
- ๋ถํ ์ ๋ณต Divide & Conquer๊ณผ ๋ฉ๋ชจ์ด์ ์ด์ Memozation์ ๊ฒฐํฉ์ ๋๋ค.
๐ค ๋ค์ด๋๋ฏน ํ๋ก๊ทธ๋๋ฐ์ ๊ณ ๋ คํ๊ธฐ
- ๋ฌธ์ ๋ฅผ ํ์ ๋ฌธ์ ๋ก ๋๋ ์ ์๋๊ฐ? - recursion
- ์ฌ๊ท๋ก ํด๊ฒฐํ๋ ๋ฌธ์ ์ธ๊ฐ? - tree
- ํ์ ๋ฌธ์ ๊ฐ ๋ฐ๋ณต์ ์ธ๊ฐ? - yes
- Memoizeํ ์ ์๋๊ฐ? - let's go!
๐ ๋ฌธ์ ๋ฅผ ์์ ํ์ ๋ฌธ์ ๋ก ์ชผ๊ฐค ์ ์๊ณ , ๋ฐ๋ณต์ ์ธ ์ฌ๊ท ํด๊ฒฐ์ฑ ๋ค์ ํด๊ฒฐ์ฑ ๋๋ ๊ฒฐ๊ณผ๋ฅผ ์บ์ฑํ์ฌ, ์ฑ๋ฅ์ ๊ฐ์ ํ ์ ์์ ๋ ์ฌ์ฉํฉ๋๋ค.
1. Overlapping Subproblems ์ค๋ณต๋๋ ํ์ ๋ฌธ์
- ํฐ ๋ฌธ์ ๋ฅผ ํ์ ๋ฌธ์ ๋ก ์ชผ๊ฐญ๋๋ค.
- ํ์ ๋ฌธ์ ๋ค์ ์๋ก ์ค๋ณต๋ ์ ์์ต๋๋ค.
- ์ค๋ณต๋ ํ์ ๋ฌธ์ ๋ค์ ํ ๋ฒ๋ง ํด๊ฒฐํ๊ณ ์ ์ฅํ์ฌ, ์ค๋ณต๋ ๊ณ์ฐ์ ํผํฉ๋๋ค.
2. Optimal Substructure ์ต์ ๋ถ๋ถ ๊ตฌ์กฐ
- ๋ถ๋ถ ๋ฌธ์ ์ ์ต์ ํด๊ฒฐ์ฑ ์ ์กฐํฉํ์ฌ ์ต์ ์ ํด๊ฒฐ์ฑ ์ ๊ตฌํฉ๋๋ค.
3. Top-down + Memoization ๋ฉ๋ชจ์ด์ ์ด์ ๐
- ํ์ ๋ฌธ์ ์ ํด๊ฒฐ์ฑ ์ ์ ์ฅํ๊ณ ์ฌ์ฌ์ฉํฉ๋๋ค.
4. Bottom-up Approach
- ๋ถ๋ถ ๋ฌธ์ ์ ์ต์ ํด๊ฒฐ์ฑ ์ ๊ตฌํ ํ, ์ด๋ฅผ ์ด์ฉํ์ฌ ์ ์ฒด ๋ฌธ์ ์ ์ต์ ํด๊ฒฐ์ฑ ์ ๊ตฌํฉ๋๋ค.
Memoization
์บ์ฑ Caching
- ๋ฌธ์ ์ ๋ํ ํด๊ฒฐ์ฑ ์ ๊ธฐ์ตํฉ๋๋ค.
algorithms\dynamic-programming\memoizationDP.js
let cache = {
// property์ ์ ๊ทผ : O of One Time
1: 81,
};
function memoizedAddTo80(n) {
if (n in cache) {
return cache[n];
} else {
console.log("์ฒ๋ฆฌ ์ค...");
cache[n] = n + 80;
return cache[n];
}
}
console.log("์ฒซ ๋ฒ์งธ: ", memoizedAddTo80(1)); // 81, ์ฐ์ฐ ํ ์บ์ฑ
console.log("๋ ๋ฒ์งธ: ", memoizedAddTo80(1)); // 81, O of One
ํด๋ก์ Closer
- global ๋ณ์๊ฐ ์๋ ํด๋ก์ ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
algorithms\dynamic-programming\memoizationDPWithCloser.js
function memoizedAddTo80WithCloser(n) {
let cache = {};
return function (n) {
if (n in cache) {
return cache[n];
} else {
console.log("์ฒ๋ฆฌ ์ค...");
cache[n] = n + 80;
return cache[n];
}
};
}
const memoized = memoizedAddTo80WithCloser(); // cache ๋ณ์์ ๋ด๋ถ ํจ์ ๋ฐํ
console.log("์ฒซ ๋ฒ์งธ: ", memoized(1)); // 81, ์ฐ์ฐ ํ ์บ์ฑ
console.log("๋ ๋ฒ์งธ: ", memoized(5)); // 85, ์ฐ์ฐ ํ ์บ์ฑ
console.log("์ธ ๋ฒ์งธ: ", memoized(5)); // 85, O of One
-
ํด๋ก์ ๋ฅผ ์ด์ฉํ์ฌ cache ๊ฐ์ฒด๋ฅผ ์ ์ธํ๊ณ , ํด๋น ํจ์ ๋ด๋ถ์์๋ง ์ ๊ทผํ ์ ์๋๋ก ๋ณ์ ํ๊ฒฝ์ ์ ์ฅํฉ๋๋ค. ์ดํ ํจ์๋ฅผ ํธ์ถํ ๋๋ง๋ค ํด๋น ๋ณ์ ํ๊ฒฝ์์ cache ๊ฐ์ฒด๋ฅผ ํ์ฉํ์ฌ ์ด๋ฏธ ๊ณ์ฐ๋ ๊ฐ์ ๋ฐํํ๊ฒ ๋ฉ๋๋ค. ์ด๋ ๊ฒ ํจ์ผ๋ก์จ, ์ ์ญ ๋ณ์๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ ๊ฐ์ ์บ์ฑํ๊ณ ์ฌ์ฌ์ฉํจ์ผ๋ก์จ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
- ์คํ ์ปจํ
์คํธ ๋ด๋ถ์ ๋ณ์ ํ๊ฒฝ์ ๊ฐ์ฒด๋ฅผ ์ ์ฅํฉ๋๋ค.
โ๏ธ ์คํ ์ปจํ ์คํธ
์ฝ๋ ์คํ์ ํ์ํ ๋ณ์, ํจ์ ์ ์ธ, ๋งค๊ฐ๋ณ์ ๋ฑ์ ์ ๋ณด๋ฅผ ๋ด๊ณ ์๋ ์คํ(Stack) ์๋ฃ๊ตฌ์กฐ ํํ(LIFO)
- ๊ตฌ๋ถ: Variable Environment, Lexical Environment, This Binding
- ์์ฑ: ์ฝ๋๋ฅผ ์คํํ ๋
- ์ ๊ฑฐ: ํจ์ ์คํ์ด ์ข ๋ฃ๋ ๋
- ์คํ ์ปจํ
์คํธ ๋ด๋ถ์ ๋ณ์ ํ๊ฒฝ์ ๊ฐ์ฒด๋ฅผ ์ ์ฅํฉ๋๋ค.
-
ํด๋ก์ ํจ์๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ ์ ์๋ ์ด์ ๋ฅผ ๋ฌป๋๋ค๋ฉด...
console.log("์ฒซ ๋ฒ์งธ: ", memoizedAddTo80WithCloser()(1)); console.log("๋ ๋ฒ์งธ: ", memoizedAddTo80WithCloser()(1));
โ๏ธ **
memoizedAddTo80WithCloser()
**ํจ์๋ ๋ด๋ถ์์ ์บ์ฑ์ ์ํ **cache
**๋ณ์์ ๋ด๋ถ ํจ์๋ฅผ ๋ฐํํฉ๋๋ค.๋งค๋ฒ
memoizedAddTo80WithCloser()
ํจ์๊ฐ ํธ์ถ๋ ๋๋ง๋คcache
๊ฐ์ฒด๊ฐ ์ด๊ธฐํ๋ฉ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์cache
๊ฐ์ฒด์ ์ ์ฅ๋ ๊ฐ์ ์ฌ์ฌ์ฉ๋์ง ์๊ณ ๋งค๋ฒ ์๋ก ๊ณ์ฐ๋ฉ๋๋ค.์ฆ,**
memoizedAddTo80WithCloser()(1)
**๊ณผmemoizedAddTo80WithCloser()(1)
์ ๊ฒฐ๊ณผ๋ ์๋ก ๋ค๋ฅผ ์ ์์ต๋๋ค.๋ณ์๋ฅผ ํจ์๊ฐ ์ต์ด ํธ์ถ๋ ๋ cache ๊ฐ์ฒด๊ฐ ์์ฑ๋๊ณ , ์ดํ ํธ์ถ์์ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฌ์ฉํ๋ ์บ์ฑ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Fibonacci ํผ๋ณด๋์น ๋ฐฐ์ด
Recursion ์ฌ๊ท๋ฅผ ์ฌ์ฉํ๋ ํผ๋ณด๋์น ๋ฐฐ์ด
- O(2^N) : O of Two the the power of N
- 9๋ฒ์งธ index๋ฅผ ๊ตฌํ๊ธฐ ์ํด, 109๋ฒ์ ๊ณ์ฐ์ด ํ์ํจ
- 20๋ฒ์งธ index๋ฅผ ๊ตฌํ๊ธฐ ์ํด, 21891๋ฒ์ ๊ณ์ฐ์ด ํ์ํจ
let cacluations = 0;
function fibonacci(n) {
cacluations++;
if (n < 2) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
const fibonacciIndex = 9;
const fibonacciNumber = fibonacci(fibonacciIndex);
console.log(`
fibonacciIndex: ${fibonacciIndex},
fibonacciNumber: ${fibonacciNumber},
cacluations: ${cacluations}
`);
ํผ๋ณด๋์น์ Dynamic Programming : ๋ฐ๋ณต๋๋ ํ์ ๋ฌธ์ ์ ํด๊ฒฐ์ฑ
- ๋ฐ๋ณต๋๋ ํ์ ๋ฌธ์
- ํ์ ๋ฌธ์ ์ ๊ณ์ฐ์ ์บ์ฑํ์ฌ ์ต์ ํํ ์ ์์ต๋๋ค.
- fib(1), fib(2), fib(3)โฆ ์ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ๋ณต๋ฉ๋๋ค.
- ํ์ ๋ฌธ์ ์ ๊ณ์ฐ์ ์บ์ฑํ์ฌ ์ต์ ํํ ์ ์์ต๋๋ค.
๋์ ํ๋ก๊ทธ๋๋ฐ์ ๋ฉ๋ชจ์ด์ ์ด์ ์ ์ฉํ๊ธฐ
๐ Top-down ๋ฐฉ์์ ์ผ๋ฐ์ ์ผ๋ก ์ฌ๊ท์ ์ธ ๋ฐฉ์์ผ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ์์์ ์์ํฉ๋๋ค. ํ์ง๋ง ์ด๋, ์ค๋ณต๋๋ ๊ณ์ฐ์ ํผํ๊ธฐ ์ํด memoization(๋ฉ๋ชจ์ด์ ์ด์ )์ ์ ์ฉํฉ๋๋ค.
์ฆ, ๋ฌธ์ ๋ฅผ ์ฌ๊ท์ ์ผ๋ก ํด๊ฒฐํ๋ฉด์ ์ด๋ฏธ ๊ณ์ฐํ ๊ฒฐ๊ณผ๋ฅผ ๋ฉ๋ชจํด ๋๊ณ , ๊ฐ์ ๊ณ์ฐ์ด ๋ค์ ๋ํ๋๋ฉด ๋ฉ๋ชจํ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํดํ๋ ๋ฐฉ์์ ๋๋ค. ์ด๋ฅผ ํตํด ์ค๋ณต ๊ณ์ฐ์ ํผํ ์ ์์ด์ ๊ณ์ฐ ์๋๋ฅผ ๋ํญ ๊ฐ์ ํ ์ ์์ต๋๋ค.
- Top down + memoization ๋ฐฉ์ / ํํฅ์ ์๊ธฐ๋ฒ
algorithms\dynamic-programming\fibonacciDP.js
let cacluations = 0;
function fibonacciFn() {
let cache = {}; // ํด์ ํ
์ด๋ธ์ ํผ๋ณด๋์น ๊ณ์ฐ๊ฐ์ ์บ์ฑํฉ๋๋ค.
return function fib(n) {
cacluations++;
if (n in cache) {
return cache[n];
} else {
if (n < 2) {
return n;
} else {
cache[n] = fib(n - 1) + fib(n - 2);
return cache[n];
}
}
};
}
const fibDP = fibonacciFn(); // ๋ณ์์ ํจ์๋ฅผ ํ ๋น
const fibonacciIndex = 20;
const fibonacciNumber = fibDP(fibonacciIndex);
// if fibonacciIndex: 9, cacluations: 109
// O of Two to the Power of N
console.log(`
Caculate Fibonacci with DP
-----------------------------
fibonacciIndex: ${fibonacciIndex},
fibonacciNumber: ${fibonacciNumber},
cacluations: ${cacluations}
`);
ํผ๋ณด๋์น ๋ฐฐ์ด : O(**2^n**) โ O(n)
- ๋ค์ด๋๋ฏน ํ๋ก๊ทธ๋๋ฐ์ ํตํด ๋ชจ๋ ์ฐ์ฐ๋ฅผ ํ ๋ฒ์ฉ ์คํํ๋, O(n)์ ์๋๋ฅผ ๊ฐ์ง๋๋ค.
- ๊ณต๊ฐ ๋ณต์ก์ฑ Space Complexity์ด ์ฌ๋ผ๊ฐ
- ์๊ฐ ๋ณต์ก์ฑ Time Complexity์ด ๋ฎ์์ง
- ํผ๋ณด๋์น๋ ์๊ฐ ๋ณต์ก์ฑ ์ ์ฝ์ด ์์ฃผ ํฐ ๊ฒฝ์ฐ์ ๋๋ค.
๋ค๋ฅธ ๋ฐฉ๋ฒ : Bottom up
๐ Bottom-up ๋ฐฉ์์ ๋์ ํ๋ก๊ทธ๋๋ฐ์ ์ฃผ์ด์ง ๋ฌธ์ ์ ํด๊ฒฐ์ ์ํด, ์์ ๋ถ๋ถ ๋ฌธ์ ๋ค์ ํด๊ฒฐ์ ๋จผ์ ๊ตฌํ๊ณ , ์ด๋ค์ ํด๊ฒฐ ๊ฒฐ๊ณผ๋ฅผ ์ด์ฉํ์ฌ ๋ณด๋ค ํฐ ๋ฌธ์ ์ ํด๊ฒฐ์ ์ฐจ๋ก๋๋ก ๊ตฌํด๋๊ฐ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
-
Bottom-up ๋์ ํ๋ก๊ทธ๋๋ฐ์ ์ฃผ์ด์ง ๋ฌธ์ ์ ํด๊ฒฐ์ ์ํด, ์์ ๋ถ๋ถ ๋ฌธ์ ๋ค์ ํด๊ฒฐ์ ๋จผ์ ๊ตฌํ๊ณ , ์ด๋ค์ ํด๊ฒฐ ๊ฒฐ๊ณผ๋ฅผ ์ด์ฉํ์ฌ ๋ณด๋ค ํฐ ๋ฌธ์ ์ ํด๊ฒฐ์ ์ฐจ๋ก๋๋ก ๊ตฌํด๋๊ฐ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
- Bottom-up ๋ฐฉ์์ ์ผ๋ฐ์ ์ผ๋ก ์ฌ๊ท ํธ์ถ์ ๋นํด ๋ฐ๋ณต๋ฌธ์ ์ฌ์ฉํ์ฌ ๊ตฌํํ๋ ๊ฒ์ด ํจ์จ์ ์ ๋๋ค.
- ์ฝ๋๊ฐ ๋ ๋ณต์กํด์ง ์ ์์ผ๋, ๋ชจ๋ ๋ถ๋ถ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ ์ต์ข ๊ฒฐ๊ณผ๋ฅผ ์ป์ด๋ด๋ ๊ณผ์ ์ด ๋ช ํํ๊ณ ์ง๊ด์ ์ด๊ธฐ ๋๋ฌธ์, ์ํฉ์ ๋ฐ๋ผ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
-
ํผ๋ณด๋์น ์์
// fibonacciBottomUp ํจ์ ์ ์, n์ ์ธ์๋ก ๋ฐ์ function fibonacciBottomUp(n) { // ์ด๊ธฐ๊ฐ ์ค์ let answer = [0, 1]; for (let i = 2; i <= n; i++) { answer.push(answer[i - 2] + answer[i - 1]); // i-2๋ฒ์งธ์ i-1๋ฒ์งธ ํญ์ ๋ํ ๊ฐ์ answer ๋ฐฐ์ด์ ์ถ๊ฐ } // ๊ตฌํ ๊ฐ๋ค ์ค n๋ฒ์งธ ๊ฐ ๋ฐํ return answer.pop(); }
๐ ํจ์ ๋ด๋ถ์์ answer ๋ฐฐ์ด์ ์ ์ธํ๊ณ , ์ด๊ธฐ๊ฐ์ผ๋ก [0, 1]์ ํ ๋นํฉ๋๋ค. ์ดํ for ๋ฌธ์ ํตํด ๋ฐฐ์ด์ ์ถ๊ฐํ ๊ฐ์ ๊ณ์ฐํ๋ฉฐ, ๋ง์ง๋ง์ answer.pop()์ ํตํด n๋ฒ์งธ ํญ์ ๋ฐํํฉ๋๋ค.
Bottom-up ๋ฐฉ์์์๋ ๊ณ์ฐํด์ผ ํ๋ ๊ฐ์ ์์ ๋จ์๋ถํฐ ๊ณ์ฐํด๋๊ฐ๊ธฐ ๋๋ฌธ์ ์ฌ๊ท ํธ์ถ์ ๋นํด ๋ ๋น ๋ฅธ ์๋๋ก ์์ด์ ๊ตฌํ ์ ์์ต๋๋ค.
๊ฒฐ๋ก ๐ฑ
- ์ฌ๊ท๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ๋ณต์ ์ธ ์ฐ์ฐ์ ํ๋ ํจ์์ ๋์ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฒ์ ์ฌ์ฉํ ์ ์๋ค.
- closer๋ฅผ ์์์ ์ผ๋ก ํ์ฉํด๋ณด์.
- ๋์ ํ๋ก๊ทธ๋๋ฐ์ ๋ํ ์์ ๋ฅผ ํ์ด๋ณด์.
- ํผ๋ณด๋์น ์์ด
- Longest Common Substring (์ต์ฅ ๊ณตํต ๋ถ๋ถ ๋ฌธ์์ด)
- 0/1 Knapsack Problem (0/1 ๋ฐฐ๋ญ ๋ฌธ์ )
- ๊ทธ๋ํ์ ์ต๋จ ๊ฒฝ๋ก
- House Robber
- Best Time to Buy and Sell Stock
- Climbing Stairs
- ์ฝ์ ๋ด์ฉ์ฒ๋ผ calcuations ํ์๋ฅผ ๊ฐ์ ํ ์ ์๋ค.