Dynamic Programming
큰 문제를 작은 문제로 나누어 푸는 문제
Divide and Conquer ( 분할정복 ) 과 차이점
작은 문제가 중복되어 일어나는지 안일어나는지입니다.
- 분할 정복 : 큰 문제를 해결하기 어려워 작은 문제로 나누어 푸는 방법 ( 작은 문제에서 반복은 없음 )
- 동적 프로그래밍 : 작은 문제들이 반복되는 것 ( 답은 바뀌지 않음 )
Dynamic Programming 방법
모든 작은 문제들은 한번만 풀어야 합니다.
정답을 구한 작은 문제를 어딘가에 메모해놓고, 다시 그보다 큰 문제를 풀어나갈 때 똑같은 작은 문제가 나타나면
메모한 작은 문제의 결과값을 이용합니다.
Dynamic Programming 조건
1) 작은 문제가 반복일 일어날 경우
2) 같은 문제는 구할 때마다 정답이 같음
Memoization ( 메모이제이션 )
작은 문제들이 반복되고, 이 작은 문제들의 결과값은 항상 같다는 점을 이용해 한번 계산한 작은 문제를 저장해놓고 다시 사용하는 것을 의미합니다. 피보나치로 예를 들 수 있습니다.
[ 피보나치 수열 예제 ]
피보나치는 1, 1, 2, 3, 5, 8 .. 의 수를 이루게 됩니다. 재귀로 풀게 될 경우 했던 작업을 또 해야하므로 일정 수 이상의 순열을 구하기가 어렵습니다.
- 점화식 : [이전 수열] + [두 단계 전 수열의 합]
- DP 조건이 해당되는지 확인
1) 작은 문제들이 반복된다.
: F(5) = F(4) + F(3) , F(4) = F(3) + F(2) 로 F(3) 이라는 수열이 F(4), F(5) 에서 반복됩니다.
2) 같은 문제를 구할때 마다 정답이 같다.
: 첫번째, 두번째 수열은 각각 1로 고정되어 있습니다. 즉, 3번째 수열은 항상 결과가 2입니다. 그리고 4번째 수열은 3번째와 2번째
수열을 이용해 구하므로 언제나 정답이 같습니다.
public class fibonacci {
static long[] memo;
public static int fibonacci_rec(int n) { // 재귀
if (n <= 1) {
return n;
} else {
return fibonacci_rec(n-1) + fibonacci_rec(n-2);
}
}
public static long fibonacci_memoization(int n) { // 메모이제이션
if (n <= 1) {
return n;
}
else if(memo[n] != 0){
return memo[n];
}
else {
return memo[n] = fibonacci_memoization(n - 1) + fibonacci_memoization(n - 2);
}
}
public static void main(String[] args) {
memo = new long[10];
System.out.println(fibonacci_rec(10));
System.out.println(fibonacci_memoization(10));
}
}
[ 재귀와의 차이점 ]
기존 재귀함수와는 다르게 이미 계산된 값을 Memo 라는 배열에 저장하여 사용한다는 차이점이 있습니다.
Bottom-up , Top-down
1. Bottom-up
작은 문제부터 구해가는 방법입니다.
public static int bottomUp(int n){
int[] arr = new int[n];
arr[0] = 0;
arr[1] = 1;
if(n==0) return arr[0];
else if(n==1) return arr[1];
else{
for(int i=2; i<=n; i++){
arr[i] = arr[i - 1] + arr[i - 2];
}
return arr[n];
}
}
2. Top-down
재귀함수로 구현하는 경우 대부분이 top-down이라고 생각하면 됩니다. 큰 문제를 풀 때 작은 문제가 아직 풀리지 않았다면 그제서야 작은 문제를 해결하게 됩니다.
* Top-down / Bottom-up 의 장점
- Top-down : 소스의 가독성이 증대
- Bottom-up : 풀기는 쉽지만 소스의 가독성이 안좋음
'알고리즘' 카테고리의 다른 글
시뮬레이션과 완전탐색 (0) | 2022.10.10 |
---|---|
DFS 코드 이해하기 ( java ) (1) | 2022.10.06 |
후위 표기식 (0) | 2022.09.25 |
decryptCaesarCipher (0) | 2022.08.09 |
인접 행렬 길찾기 (0) | 2022.08.04 |