오늘은 거두절미하고, DP(Dynamic Programming) 알고리즘에 대해서 알아보고자 한다.
여기서 설명하는 DP 알고리즘은 동적 할당과는 다른 개념이므로, 착각하지 말자
동적할당은 메모리 공간에 동적으로 (런타임에) 변수 공간을 할당한다는 개념이며,
동적이라는 것 자체가 프로그램이 실행되는 런타임에 발생한다는 것을 이해하면 된다.
DP 알고리즘을 설명할 때 주로 피보나치 수열을 예시로 들곤 한다.
피보나치 수열은 특정 점화식으로 반복되는 수열을 의미한다.
점화식은 아래와 같다.
F(n) = F(n-1) + F(n-2), 단 F(0) = 0, F(1) = 1
이러한 피보나치 수열을 코드로 구현한다면 어떨까?
# 재귀를 사용한 피보나치 수열 구현
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
코드는 매우 간단하게 구현할 수 있다.
하지만, 만약 피보나치 수열의 1000번째 숫자를 알아내고자 한다면,
위 코드로는 얼마나 걸릴까?
해당 코드는 O(2^n)이라는 시간복잡도를 갖고 있다.
따라서 현 컴퓨터 구조로는 우리의 수명이 다할 때까지도 계산을 마칠 수 없을 것이다.
이러한 경우에 사용되는게 DP 알고리즘이다.
DP알고리즘을 적용할 수 있는 문제의 특징을 2가지가 있다.
1. 큰 문제를 작은 문제로 나눌 수 있다.
2. 작은 문제로 구한 정답은 그것을 포함하는 큰 문제에서도 정답이 달라지지 않는다.
피보나치 수열이 위 조건을 만족하는 대표적인 문제이다.
이 문제를 Memoization(메모이제이션) 기법을 활용하여 해결해보자.
(메모이제이션 기법은 저장한 정보를 그대로 가져와서 사용한다는 점에서 caching 이라고도 불린다.)
# 메모이제이션을 사용한 피보나치 수열 구현 (Top-Down 방식)
memo = {}
def fibonacci_memo(n):
if n <= 1:
return n
if n not in memo:
memo[n] = fibonacci_memo(n-1) + fibonacci_memo(n-2)
return memo[n]
위 코드로 수행하면 O(N)의 시간복잡도로 문제를 빠르게 해결할 수 있음을 알 수있다.
이렇게 다이나믹 프로그래밍이란 큰 문제를 작게 나누고, 같은 문제라면 한 번씩만 풀어서
문제를 효육적으로 해결하는 알고리즘 기법이다.
여기서 추가적으로 재귀함수 방식으로 DP를 구현하게 된다면,
컴퓨터 시스템에서는 함수를 다시 호출했을 때 메모리 상에 적재되는 오버헤드가 발생할 수 있다.
따라서 재귀함수 대신에 반복문으로 구현하게 된다면 오버헤드를 줄일 수 있다.
## 반복문으로 구현한 피보나치 ##
# 반복문을 사용한 피보나치 수열 구현 (Bottom-Up 방식)
def fibonacci_iterative(n):
if n <= 1:
return n
prev, curr = 0, 1
for _ in range(2, n + 1):
prev, curr = curr, prev + curr
return curr
이 방식은 스택 오버헤드를 피할 수 있으며, 같은 시간복잡도 O(n)으로 문제를 해결할 수 있다.
이처럼 동적 계획법에는 두 가지 접근 방식이 있다:
- Top-Down 방식: 큰 문제를 해결하기 위해 작은 문제를 재귀적으로 호출하는 방식. 메모이제이션을 통해 중복 계산을 줄인다.
- Bottom-Up 방식: 작은 문제부터 시작해 차례로 답을 쌓아올려 큰 문제를 해결하는 방식. 반복문을 사용해 구현한다.
동적 계획법은 큰 문제를 작게 나누고,
작은 문제를 한 번만 풀어 중복 계산을 방지함으로써 효율적으로 문제를 해결하는 알고리즘 기법이다.
다음 번에는 DP를 적용할 수 있는 더 다양한 문제와 그 해결 방법에 대해 살펴보자.
'CodingTest > algorithm' 카테고리의 다른 글
부분수열의 합을 구하는 알고리즘 정리 - 완전탐색, 백트래킹, DP, 비트마스크 비교 (Python) (0) | 2024.11.27 |
---|---|
브루트포스 알고리즘 살펴보기 (Brute Force) (1) | 2024.11.23 |
자료구조와 알고리즘의 시간복잡도 완벽 정리: 이진트리부터 해시 테이블까지 (0) | 2024.10.17 |
이진탐색(Binary Search) 알고리즘 개념 및 구현 (0) | 2024.10.01 |
자료구조 - 스택(Stack), 큐(Queue) 개념 정리 (0) | 2024.09.25 |