복잡한 문제를 더 간단한 하위 문제의 모음으로 쪼개서 푸는 프로그래밍 방식을 뜻한다.
Memoization
: 하향식 접근 Tabulation
: 상향식 접근: 동적 프로그래밍을 쓰기 위해서는 그 문제에 중첩되는 하위 문제가 있어야 한다.
(문제를 더 작은 문제로 쪼개고 그 문제가 재활용될 수 있는 형태.)
ex. 피보나치 수열
: 하위 문제의 최적 해답을 통해서 더 큰 범주의 문제의 최적 해답을 구할 수 있는 경우
ex. 피보나치 수열, 최단경로
function fib(n){
if(n <= 2) return 1;
return fib(n-1) + fib(n-2);
}
시간 복잡도 : O(2^n) 으로, 매우 안좋다.
- 입력값이 100 정도만 넘어가도 stack overflow 발생.
반복적으로 계산되는 것들의 계산 횟수를 줄이기 위해 이전에 계산했던 값을 저장해두었다가 나중에 재사용하는 방법. (하향식 접근)
function fib(n, memo = [undefined,1,1]){
if(memo[n] !== undefined) return memo[n];
var res = fib(n-1, memo) + fib(n-2, memo);
memo[n] = res;
return res;
}
ex. fib(5)
fib(3)
, fib(4)
, fib(5)
를 순서대로 구해서 배열에 담는다.fib(1)
, fib(2)
는 배열에 초기값으로 미리 넣어두었으므로 패스한다.)fib(3)
를 구할 때에는 fib(1) + fib(2)
를 다시 계산하지 않고, 기존에 있는 fib(3)
를 배열에서 가져와 쓴다.시간 복잡도 : O(n)으로 개선
가장 작은 하위 문제를 풀어 테이블(배열, 객체 등)에 저장하고, 루프를 사용해 값을 상향식으로 구해나간다. (상향식 접근)
function fib(n){
if(n <= 2) return 1;
var fibNums = [undefined, 1, 1];
for(let i=3; i<=n; i++){
fibNums[i] = fibNums[i-1] + fibNums[i-2];
}
return fibNums[n];
}
ex. fib(6)
시간 복잡도는 두 방식 모두 O(n)이지만, 공간 복잡도는
Tabulation
방식이 더 좋다.
- 입력값을 매우 크게 넣으면
Memoization
방식에서는stack overflow
가 발생하지만,Tabulation
방식에서는stack overflow
가 발생하지 않는다.
(다만, 자바스크립트 정수 범위를 넘어가면Infinity
로 표현된다.)Memoization
에서는 재귀를 사용했기 때문에 스택에서 대기하고 있는 해결되지 않은 재귀 호출들이 많다. 그러나,Tabulation
에서는 재귀를 사용하지 않아 공간 복잡도가 더 낮다.
참고 https://www.zerocho.com/category/Algorithm/post/584b979a580277001862f182