분할 정복: 작은 문제의 중복이 없다.
다이나믹 프로그래밍: 작은 문제의 중복이 있다.
다이나믹 프로그래밍의 대표적인 예인 피보나치 수를 구하는 경우로 두가지 방식을 살펴보자.
javascript code
// question: 구하려는 수의 값
const arr = Array(question + 1).fill(0);
const fibonacci = (number) => {
if(number === 0) return 0;
if(number === 1) return 1;
if(arr[number] !== 0) return arr[number];
arr[number] = fibonacci(number - 1) + fibonacci(number - 1);
return arr[number];
}
console.log(fibonacci(question));
java code
// question: 구하려는 수의 값
int[] arr = new int[question + 1];
System.out.print(fibonacci(question));
static int fibonacci(int number) {
if(number == 0) return 0;
if(number == 1) return 1;
if(arr[number] != 0) return arr[number];
arr[number] = fibonacci(number - 1) + fibonacci(number - 1);
return arr[number];
}
javascript code
// question: 구하려는 수의 값
const arr = [0, 1];
for(let i = 2; i < question + 1; i++) {
arr.push(arr[i - 1] + arr[i - 2]);
}
console.log(arr[question]);
java code
// question: 구하려는 수의 값
ArrayList<Integer> arr = new ArrayList<>();
arr.add(0);
arr.add(1);
for(int i = 2; i < question + 1; i++) {
arr.add(arr.get(i - 1) + arr.get(i - 2));
}
System.out.print(arr.get(question));
결론부터 말하면 본인이 편한걸 사용하자.
구조적인 관점으로 봤을 때는 Top-down을 사용했을 경우 재귀 덕분에 Stack Overflow가 발생할 수 있고 반복문을 사용하는 Bottom-up이 더 빠르다고 볼 수 있지만 어떤게 더 좋다고 확실하게 말 할 수 없다.
Stack Overflow가 발생할 경우 다이나믹 프로그래밍을 잘못 구현했을 확률이 높고 Top-down은 모든 문제를 풀어보지 않아도 답이 나오는 경우가 있기 때문이다.
정리하자면 문제를 잘 파악하고 적합한 방식을 적용하는 것이 좋겠지만 어렵게 생각하지 말고 둘 중 하나를 정확하게 사용하는 것이 가장 중요하다.
더군다나 Top-down과 Bottom-up은 대부분의 경우에 서로 대체 가능하다.
다이나믹 프로그래밍을 많이 풀어본 것은 아니지만 풀 때마다 새롭게 느껴진다.
문제마다 구해야 하는 점화식이 다르고 해당 점화식을 파악하기가 쉽지 않기 때문에 더욱 그렇게 느껴지는 것 같다.
해야할 것은 작은 문제로 나누는 것을 이해하는 것과 당연하게도 많이 풀어보는 것이다.
오맛 멋져요~