항해99, 5주차 다이나믹프로그래밍

Jang Seok Woo·2022년 2월 13일
0

알고리즘

목록 보기
65/74

Today I learned
2022/02/09

회고록


2/09

항해 99, 알고리즘 4주차(항해 5주차)

교재 : 파이썬 알고리즘 인터뷰 / 이것이 코딩테스트다(동빈좌)

다이나믹 프로그래밍

1. 이론

다이나믹 프로그래밍은 동적 계획법이라고도 부른다

일반적인 프로그래밍 분야에서의 동적(Dynamic)이란 어떤 의미를 가질까?

자료구조에서 동적 할당(Dynamic Allocation)은 '프로그램이 실행되는 도중에 실행에 필요한
메모리를 할당하는 기법'을 의미한다
반면에 다이나믹 프로그래밍에서 '다이나믹'은 별다른 의미 없이 사용된 단어이다
다이나믹 프로그래밍은 다음의 조건을 만족할 때 사용할 수 있다

최적 부분 구조 (Optimal Substructure)
큰 문제를 작은 문제로 나눌 수 있으며 작은 문제로 나눌 수 있으며 작은 문제의 답을 모아서 큰 문제를 해결할 수 있다
중복되는 부분 문제 (Overlapping Subproblem)
동일한 작은 문제를 반복적으로 해결해야 한다

피보나치 수열
피보나치 수열 다음과 같은 형태의 수열이며, 다이나믹 프로그래밍으로 효과적으로 계산할 수 있다

1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

점화식이란 인접한 항들 사이의 관계식을 의미

피보나치 수열을 점화식으로 표현하면 다음과 같음

링크텍스트

피보나치 수열이 계산되는 과정은 다음과 같이 표현할 수 있다
프로그래밍에서는 이러한 수열을 배열이나 리스트를 이용해 표현한다

링크텍스트

피보나치 수열이 계산되는 과정은 다음과 같이 표현할 수 있다
𝑛번째 피보나치 수를 f(𝑛)라고 할 때 4번째 피보나치 수 f(4)를 구하는 과정은 다음과 같다

링크텍스트

피보나치 수열의 시간 복잡도 분석

단순 재귀 함수로 피보나치 수열을 해결하면 지수 시간 복잡도를 가지게 된다
다음과 같이 𝒇(2) 가 여러 번 호출되는 것을 확인할 수 있다 (중복되는 부분 문제)

링크텍스트

피보나치 수열의 시간 복잡도는 다음과 같다
세타 표기법: 𝜽(1.618・・・ᴺ)
빅오 표기법: O(2ᴺ)
빅오 표기법을 기준으로 𝒇(30)을 계산하기 위해 약 10억가량의 연산을 수행해야 한다

그렇다면 𝒇(100)을 계산하기 위해 얼마나 많은 연산을 수행해야 할까?

피보나치 수열의 효율적인 해법: 다이나믹 프로그래밍
다이나믹 프로그래밍의 사용 조건을 만족하는지 확인한다
최적 부분 구조: 큰 문제를 작은 문제로 나눌 수 있다
중복되는 부분 문제: 동일한 작은 문제를 반복적으로 해결한다
피보나치 수열은 다이나믹 프로그래밍의 사용 조건을 만족한다

링크텍스트

메모이제이션 (Memoization)

메모이제이션은 다이나믹 프로그래밍을 구현하는 방법 중 하나이다
한 번 계산한 결과를 메모리 공간에 메모하는 기법이다
같은 문제를 다시 호출하면 메모했던 결과를 그대로 가져온다
값을 기록해 놓는다는 점에서 캐싱(Caching) 이라고도 한다

탑다운 VS 보텀업

탑다운(메모이제이션) 방식은 하향식이라고도 하며 보텀업 방식은 상향식이라고도 한다
다이나믹 프로그래밍의 전형적인 형태는 보텀업 방식이다
결과 저장용 리스트는 DP 테이블이라고 부른다
엄밀히 말하면 메모이제이션은 이전에 계산된 결과를 일시적으로 기록해 놓는 넓은 개념을 의미한다
따라서 메모이제이션은 다이나믹 프로그래밍에 국한된 개념은 아니다
한 번 계산된 결과를 담아 놓기만 하고 다이나믹 프로그래밍을 위해 활용하지 않을 수도 있다

피보나치 수열: 탑다운 다이나믹 프로그래밍 소스코드 (Python)

# 한 번 계산된 결과를 메모이제이션(Memoization)하기 위한 리스트 초기화
d = [0] * 100

# 피보나치 함수(Fibonacci Function)를 재귀함수로 구현 (탑다운 다이나믹 프로그래밍)


def fibo(x):
    # 종료 조건(1 혹은 2일 때 1을 반환)
    if x == 1 or x == 2:
        return 1
    # 이미 계산한 적 있는 문제라면 그대로 반환
    if d[x] != 0:
        return d[x]
    # 아직 계산하지 않은 문제라면 점화식에 따라서 피보나치 결과 반환
    d[x] = fibo(x - 1) + fibo(x - 2)
    return d[x]

print(fibo(99))

피보나치 수열: 보텀업 다이나믹 프로그래밍 소스코드 (Python)

# 앞서 계산된 결과를 저장하기 위한 DP 테이블 초기화
d = [0] * 100

# 첫 번째 피보나치 수와 두 번째 피보나치 수는 1
d[1] = 1
d[2] = 1
n = 99

# 피보나치 함수(Fibonacci Function) 반복문으로 구현(보텀업 다이나믹 프로그래밍)
for i in range(3, n + 1):
    d[i] = d[i - 1] + d[i - 2]

print(d[n])

2. 구현

# 피보나치 함수(Fibonacci Function)을 재귀함수로 구현
def fibo(x):
    if x == 1 or x == 2:
        return 1
    return fibo(x - 1) + fibo(x - 2)

print(fibo(4))

#실행 결과 3
profile
https://github.com/jsw4215

0개의 댓글