Algorithm - Dynamic Programming

2022. 11. 3. 15:40Algorithm

 

Dynamic Programming

 

Dynamic Programming(동적계획법)이란?

하나의 큰 문제를 여러개의 작은 문제로 나누어 그 결과를 저장 후 다시 큰 문제를 해결할 때 사용하는 방법이다.

쉽게 말하면 "기억하며 풀기"이다.

재귀와 유사하지만 일반적인 재귀방식으로 연산할시 동일한 작은 문제들이 여러번 호출되어 비효율적이다.

 

재귀 - 피보나치 수열

재귀의 예시로 피보나치 수열에 대해 살펴보자

//재귀 방식으로 구현한 피보나치 수열
public class fibo {
    static int count=0;
    private static int fibona(int n){
        int result = 0;
        count++;
        if(n==0) return 0;
        if(n==1) return 1;
        return fibona(n-2) + fibona(n-1);
    }
    public static void main(String[] args) {
        System.out.println(fibona(6));
        System.out.println(count);
    }
}

/* 출력 결과
8
25
*/

이 경우 fibona(6)을 호출시 8의 결과를 얻기 위해 총 15번 메소드의 호출이 이루어졌다.

파라미터의 수가 6이었기에 25번 호출이 되었지만 파라미터가 커질수록 메소드의 호출횟수는 급격하게 늘어날 것이다

그 이유는 fibona 메소드의 시간복잡도는 n이 1증가할 때마다 2배씩 늘어나므로 O(2^n)이 된다.

 

Dynamic Programming 조건

DP를 적용하기 위해서는 조건이 필요하다

1.동일한 작은 문제들이 반복해서 나타나는 경우 사용 가능

2.부분 문제의 최적 결과 값을 사용해 전체 문제의 최적 결과를 낼 수 있는 경우

 

구현 방식
  • Bottom-Up 방식 (Tabulation)
    • 아래에서부터 계산을 수행하고 누적시켜서 전체 큰 문제를 해결하는 방식 (반복문)
    • 함수를 별도로 호출하지 않아 시간과 메모리를 더 절약할 수 있다.
  • Top-Down 방식 (Memoization)
    • 위에서부터 바로 호출을 시작하여 결과 값을 재귀를 통해 전이시켜 재활용하는 방식
    • 가독성이 좋으며 점화식을 이해하기 쉬움
    • DP는 기억하며 풀기이기 때문에 이 케이스에 해당한다

 

 

1. Memoization과 recursive를 성능,가독성 면에서 비교 분석해주세요
   그리고 피보나치 수를 구하는 함수를 DP와 recurve를 이용해서 각각 구현하고 아래를 테스트 해주세요
   => f(1),  f(100) f(10000)
     * 특이사항이 있다면 원인을 분석해주세요
     
public class fibo {
    static int count=0;
    static int[] dp = new int[100];
    private static int fibona(int n){
        if(n==0) return 0;
        if(n==1) return 1;
        return fibona(n-2) + fibona(n-1);
    }

    private static int dpfibo(int n){
        if(n==1||n==2) return 1;
        if(dp[n]!=0) return dp[n];
        return dp[n] = dpfibo(n-1)+dpfibo(n-2);
    }
    public static void main(String[] args) {
        
        long beforeTime = System.currentTimeMillis();
        System.out.println(fibona(30));
        long afterTime = System.currentTimeMillis();
        System.out.println("시간차이: " +(afterTime - beforeTime));
        long before_Time = System.currentTimeMillis();
        System.out.println(dpfibo(30));
        long after_Time = System.currentTimeMillis();
        System.out.println("시간차이: " +(after_Time - before_Time));
    }
}



'Algorithm' 카테고리의 다른 글

Algorithm - 정렬  (0) 2023.07.05
Algorithm - Hash  (0) 2022.10.27
Algorithm - Graph  (0) 2022.10.20
Algorithm - 우선순위 큐(Priority Queue)  (0) 2022.10.20
Algorithm - Tree  (0) 2022.10.20