logo
Search검색어를 포함하는 게시물들이 최신순으로 표시됩니다.
    Table of Contents
    [Algorithm] 메모이제이션과 동적계획법(Memoization and DP)

    이미지 보기

    [Algorithm] 메모이제이션과 동적계획법(Memoization and DP)

    메모이제이션과 동적계획법에 대해 알아보자.

    • 22.02.21 작성

    • 읽는 데 4

    TOC

    Call Tree

    • 재귀 함수에서 구현한 알고리즘의 호출 함수들의 트리
    • 특정 알고리즘은 상당히 많은 중복 호출이 존재

    메모이제이션(Memoization)

    • 이전에 계산한 값을 메모리에 저장 → 매번 다시 계산하지 않도록 한다.
    • 동적 계획법(DP)의 핵심이 되는 기술

    알고리즘

    # memo를 위한 배열을 할당하고, 모두 0으로 초기화
    
    def fibo1(n):
        global memo
        if n >= 2 and len(memo) <= n:             # memo의 길이보다 n이 크거나 같으면, 값을 만들어야 함.
            memo.append(fibo1(n-1) + fibo1(n-2))
        return memo[n]                            # memo에 n에 해당하는 값이 있으니까 계산없이 바로 반환
    
    # memo[0]을 0으로 memo[1]는 1로 초기화
    memo = [0, 1]
    

    만약 스택처럼 메모리를 미리 선점하여 운용하고 싶다면 memo를 아래처럼 정의하면 된다.

    def fibo1(n):
        global memo
        if n >= 2 and len(memo) <= n:             # memo의 길이보다 n이 크거나 같으면, 값을 만들어야 함.
            memo.append(fibo1(n-1) + fibo1(n-2))
        return memo[n]                            # memo에 n에 해당하는 값이 있으니까 계산없이 바로 반환
    
    memo = [0]*n
    memo[1] = 1
    

    동적 계획법(DP; Dynamic Programming)

    • Greedy 알고리즘과 같이 최적화 문제를 해결하는 알고리즘

    • 입력 크기가 작은 부분 문제들을 모두 해결

    • 그 해들을 이용하여 보다 큰 크기의 부분 문제 해결

    • 최종적으로 원래 주어진 입력의 문제 해결


    피보나치 수 DP 적용

    • 피보나치 수는 부분 문제의 답으로부터 본 문제의 답을 얻을 수 있다.
    • 최적 부분 구조로 구성된다.

    구현

    N = 10
    Fibo = [0]*(N+1)
    Fibo[0] = 0
    Fibo[1] = 1
    
    for i in range(N+1):
        Fibo[i] = Fibo[i-1] + Fibo[i-2]
    
    print(Fibo)
    

    문제를 부분 문제로 분할

    Fibo(n) = Fibo(n-1) + Fibo(n-2)
    Fibo(n-1) = Fibo(n-2) + Fibo(n-3)
    
    ...
    
    Fibo(2) = Fibo(1) + Fibo(0)
    

    부분 문제로 나누었다면 가장 작은 부분 문제부터 해 구하기

    위에서는 Fibo[0]과 Fibo[1]을 각각 0과 1로 초기화한 것.


    결과를 테이블에 저장, 테이블에 저장된 부분 문제의 해를 이용해 상위 문제의 해를 구하기

    위에서는 Fibo[i-1]과 Fibo[i-2]를 통해 Fibo[i]를 구하는 과정


    DP의 구현 방식

    recursive 방식

    def Fibo1(n):
        if n < 2:
            return n
        else:
            return Fibo(n-1) + Fibo(n-2)
    

    iterative 방식

    def Fibo2(n):
        f = [0, 1]
    
        for i in range(2, n+1):
            f.append(f[i-1] + f[i-2])
    
        return f[n]
    

    특징

    • Memoization을 재귀적 구조(Fibo1(n))에 사용하는 것보다 반복적 구조(Fibo2(n))로 DP를 구현한 것이 성능 면에서 효율적
    • 재귀적 구조는 내부에 시스템 호출 스택을 사용하는 오버헤드 발생
    profile

    FE Developer 박승훈

    노력하는 자는 즐기는 자를 이길 수 없다