주어진 문제를 여러 개의 하위 문제로 나누어 풀고, 하위 문제들의 해결 방법을 결합하여 최종 문제를 해결하는 문제 해결 방식을 말합니다.
기존의 피보나치 함수의 답을 구할려고했다면 이렇게 작성했을 테지만,
function fibo(n) {
if (n == 0) return 0;
if (n == 1) return 1;
return fibo(n - 1) + fibo(n - 2);
}
중복되는 값을을 매번 일일히 계산함으로 시간복잡도가 증가합니다. 이 경우에 시간 복잡도는 O(n^2) 입니다.
이 중복을 제거하기 위해서 메모이제이션(Memoization)이라는 테크닉을 사용합니다.
function fibo(n) {
memo = [0, 1];
for (let i = 0; i <= n; i++)
memo[i] = memo[i - 1] + memo[i - 2];
return memo[n];
}
계산한 값을 배열해 저장해서 재활용합니다.
Dynamic Programming 에는 2가지 방법이 있습니다.
function fibMemo(n, memo = []) {
// 이미 해결한 하위 문제인지 찾아본다
if(memo[n] !== undefined) {
return memo[n];
}
if(n <= 2) {
return 1;
}
// 없다면 재귀로 결괏값을 도출하여 res 에 할당
let res = fibMemo(n-1, memo) + fibMemo(n-2, memo);
// 추후 동일한 문제를 만났을 때 사용하기 위해 리턴 전에 memo 에 저장
memo[n] = res;
return res;
}
function fibTab(n) {
if(n <= 2) {
return 1;
}
let fibNum = [0, 1, 1];
for(let i = 3; i <= n; i++) {
fibNum[i] = fibNum[i-1] + fibNum[i-2];
// n >= 3 부터는 앞서 배열에 저장해 놓은 값들을 이용하여
// n번째 피보나치 수를 구한 뒤 배열에 저장 후 리턴한다
}
return fibNum[n];
}
const coinChange = function (total, coins) {
const makeChange = (left, idx) => {
if (total === 0) { return 1};
else {
let cnt = 0;
for (let i = idx; i < coins.length; i++) {
cnt = cnt + makeChange(left - coins[i], i);
}
}
return cnt;
} //left에는 total 값이 들어갑니다.
}return makeChange(total, 0);
coinChange가 결국 return 하는 값은 cnt = cnt + cnt + cnt...1 입니다.
const coinChange = function (total, coins) {
const memo = [] // memoization 기록할 곳
for (let i = 0; i < total +1; i++) {
memo.push(Array(coins.length).fill(-1))
} // -1로 채운 coins 수만큼 배열을 memo에 만듭니다
const makeChange = (left, idx) => {
if (left === 0) { return 1} ; // 필요충족조건에 도달했을 때!
else if (left < 0) { return 0 } ; // total 금액보다 더 많이 빼버린 경우, 조건을 충족하지못해서 횟수로 계산하지않습니다.
else if (idx >= coins.length && left > 0) return 0 // toal 금액보다 모지란 경우 역시도, 조건을 충족하지못했기 때문에 횟수로 인정하지않습니다.
}
else if (memo[left][idx] !== -1) { return memo[left][idx]};
// 해결하지못한 문제는 다시 풀지 않습니다.
memo[left][idx] = makeChange(left, idx+1) + makeChange(left - coins[idx], idx);
}
return makeChange(total, 0)
}
const coinChange = function (total, coins) {
const table = []
for (let i = 0; i < total+1; i++) {
table.push(Array(coins.length).fill(0))
}
for (let i = 0; i < coins.length; i++) {
table[0][i] = 1;
}
for (let amount = 1; amount <= total; amount++) {
for (let idx = 0; idx < coins.length; i++) {
let coinInclude = 0;
if (amount - coins[idx] >= 0) {
coinInclude = table[amount - coins[idx]][idx];
}
let coinExclude = 0;
if (idx >= 1) {
coinExclude = table[amount][idx -1];
}
table[amount][idx] = coinInclude + coinExclude
}
}
return table[total][coins.length -1]
}