개발 공부 기록

Dynamic programming이란? 본문

PS/Concept

Dynamic programming이란?

나만없서고냥이 2023. 9. 14. 17:14

Dynamic programming이란 한 번 계산한 문제는 다시 계산하지 않도록 하는 알고리즘으로, 중복 계산을 피하기 위해 실행 중간중간의 결과를 저장하고 이를 재사용하는 방식입니다. 어떠한 큰 문제를 작은 하위 문제로 분할하여 큰 문제의 최적 해결 방법을 하위 문제의 최적 해결 방법을 조합하여 만들어냅니다. 

 

피보나치 수열을 예로 들어보겠습니다.

public static int fibo(int x) {
	if(x == 1 || x == 2) {
		return 1;
	}
    return fibo(x - 1) + fibo(x - 2);
}

fibo(6)을 생각해봅시다. fibo(6)은 fibo(5)와 fibo(4)를 호출하고 fibo(5)는 fibo(4)와 fibo(3)을, fibo(4)는 fibo(3)과 fibo(2)를 호출합니다. 이때 fibo(5)가 호출한 fibo(4)는 fibo(3)과 fibo(2)를 또 호출하게 됩니다. 이때 fibo(3)이나 fibo(2)와 같이 반복적으로 호출되는 것을 볼 수 있는데, 여기서 x 값이 더욱 커지면 반복해서 호출되는 것은 훨씬 많아질 것입니다.

 

이러한 문제는 Dynamic programming을 사용하면 효율적으로 해결할 수 있습니다. 다만 아래 조건을 만족할 때 Dynamic programming이 사용 가능합니다.

1. 큰 문제를 여러 하위 문제로 나눌 수 있다.
2. 하위 문제에서 구한 정답은 그것을 포함하는 큰 문제에서도 동일하다.

피보나치 수열은 이러한 조건을 만족하는 대표적인 문제입니다. 

 

 

 

📝메모제이션 기법이란?

메모이제이션(Memoization)은 Dynamic programming을 구현하는 방법 중 하나로, 계산한 결과를 메모리에 저장하여 동일한 계산이 필요한 경우 이전에 계산한 값을 재사용하는 기법입니다. 즉, 값을 저장하는 방법으로 캐싱(Caching)이라고도 합니다.

 

메모제이션을 구현하는 방법은 한 번 구한 정보를 리스트에 저장하기만 하면 됩니다. Dynamic programming을 재귀적으로 수행하다가 같은 정보가 필요하면 이미 구한 정잡을 리스트에서 그대로 가져오면 됩니다. 

public class FibonacciMemoization {
    // 계산된 결과를 저장할 배열
    static int[] memo;

    public static int fibo(int x) {
        if (x == 1 || x == 2) {
            return 1;
        }

        // 이미 계산한 값이 있으면 바로 반환
        if (memo[x] != 0) {
            return memo[x];
        }

        // 아직 계산한 적 없는 경우, 피보나치 값을 계산하고 메모에 저장
        memo[x] = fibo(x - 1) + fibo(x - 2);
        return memo[x];
    }

    public static void main(String[] args) {
        int n = 10;
        memo = new int[n + 1];

        int result = fibo(n);
        System.out.println("Fibonacci(" + n + ") = " + result);
    }
}

 

 

Top-Down 방식⬇️ &  Bottom-up 방식⬆️

Top-Down 방식은 재귀적으로 문제를 해결하면서 중간 결과를 저장하고 나중에 재사용하는 방식으로, 큰 문제를 해결하기 위해 작은 문제를 호출합니다. 이는 재귀 함수를 사용하여, 메모리 상에 적재되는 일련의 과정을 따라야 하기 때문에 오버헤드가 발생할 수도 있습니다. (메모제이션은 이 Top-Down 방식에 국한되어 사용되는 표현이라는 것을 기억합시다.) 

 

Bottom-Up 방식은 하위 문제부터 시작하여 큰 문제로 진행하며, 중간 결과를 테이블에 저장하는 방식입니다. 이때 이 테이블을 DP 테이블이라고 하며 결과 저장용 리스트라고 생각하시면 됩니다. 주로 반복문을 사용하여 모든 하위 문제에 대한 결과를 한 번에 계산하고 저장하기 때문에 메모리 사용량이 더 효율적입니다. 

 

따라서 Dynamic programming을 구현할 때 입력 크기가 크거나 성능이 중요한 경우에는 Bottom-Up 방식이 유용할 수 있습니다.

'PS > Concept' 카테고리의 다른 글

분할 정복(Divide and Conquer)  (0) 2023.11.27
DFS와 BFS  (0) 2023.08.09
이분 탐색(Binary Search)  (0) 2023.08.02