Greedy의 사전적 정의는 "탐욕스러운, 욕심 많은" 이란 뜻을 지니고 있습니다. 말 그대로 탐욕 알고리즘은 결정의 순간마다 당장 눈앞에 보이는 최적의 상황만을 선택하여 해답에 도달하는 방법입니다. 대표적인 예시로는 거스름돈을 나눠주는 방법이 있습니다. 이를 로직으로 적어보면
코드스테이츠에서 나온 탐욕알고리즘(Greedy) 문제로 짐나르기 코플릿에서의 저의 로직을 적어보겠습니다. 용량제한이 있는 박스를 최대한 덜 쓰고 짐을 나눌 때 박스의 개수를 구해야 합니다. 해당 함수의 받는 인자로 짐의 무게를 적은 배열, 용량제한 값입니다.
동적계획법이라고 불리는 Dynamic Programming은 모든 경우의 수를 따져본 후에 이를 조합해 최적의 해법을 찾는 방식입니다. 주어진 문제를 여러 개의 하위 문제로 나누어 풀고, 하위 문제들의 해결 방법을 결합하여 최종 문제를 해결하는 문제 해결 방식에서 하위 문제를 계산한 뒤 그 해결책을 저장하여, 후에 같은 하위 문제가 나왔을 경우 저장된 해결책을 이용하여 계산 횟수를 줄임으로써 비효율적인 알고리즘을 개선하는 방법입니다. 즉, 하나의 문제는 단 한 번만 풀도록 하는 알고리즘이 바로 이 다이내믹 프로그래밍입니다.
주어진 문제를 여러 개의 하위 문제로 나누어 풀고, 하위 문제들의 해결 방법을 결합하여 최종 문제를 해결하는 대표적인 예시로는 피보나치가 있습니다.
function fibonacci(num) {
if(num === 0){
return 0;
}
if(num === 1){
return 1;
}
return fibonacci(num - 1) + fibonacci(num - 2);
}
여기서
fibonacci(5)를 하게되면 fibonacci(4) + fibonacci(3) = fibonacci(3) + fibonacci(2) +fibonacci(3)... 이런식으로 같은 값이 반복되어 나옵니다. 만약 num의 값이 5가 아니라 100, 1000, 10000이면 중복되는 함수실행이 더욱 늘어나게 되고 매우 비효율적인 계산 방식이라고 생각합니다. 그렇기 때문에 기존에 값이 나왔던 적이 있다면 그 값을 저장하여 값을 바로 활용할 수 있게 만든는 것이 Dynamic Programming입니다.
function fibMemo(n, memo = []) {
if(memo[n] !== undefined) {
return memo[n];
}
if(n <= 2){
return 1;
}
let res = fibMemo(n-1, memo) + fibMemo(n-2, memo);
memo[n] = res;
return res;
}
메모 배열을 추가해 줌으로써 값을 저장할 공간을 설정한뒤 기존에 한번 나왔던 값이면 그 값을 메모 배열에 저장함으로써 반복되는 계산을 줄일 수 있습니다.