일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- level1
- 8-Puzzle
- Modern C++
- Bronze
- effective C++
- knapsack Problem
- 프로그래머스
- BFS
- stack
- level3
- two pointer
- Zenject
- algorithm
- BOJ
- Euclidean
- Unity
- LEVEL2
- 3D RPG
- programmers
- 프로세스 상태
- Flyweight Pattern
- solid 원칙
- Silver
- dirtyflag pattern
- Gold
- binary search
- SWEA
- trie
- PrefixSum
- Project
- Today
- Total
Patrick's Devlog
[Algorithm] Dynamic Programming 본문
개요
조금씩 알고리즘 공부를 진행하고 있던 중에, DP에 대해 이미 공부를 했지만 아직 많이 빈약한 것 같아 유튜브를 통해 인강을 들은 후 다시 한 번 정리하려고 한다. 강의는 코드없는 프로그래밍님의 Dynamic Programming이다. 강의를 듣고싶다면 아래의 링크로 들어가면 들을 수 있다.
https://www.youtube.com/watch?v=eJC2oetXaNk
Dynamic Programming
다이나믹 프로그래밍은 세가지 조건이 충족되면 바로 적용이 가능하다
1. Problem이 더 작은 subproblem으로 쪼개질 때
2. 이런 subproblem들의 솔루션으로 더 큰 규모의 problem의 솔루션을 구할 수 있을 때
3. 이러한 subproblem들이 겹칠 때 -> memorization 이용 가능
강의에서는 피보나치 수열로 예를 들어주었다.
위의 그림에서 subproblem을 확인할 수 있으며, 동일한 subpromblem 또한 확인할 수 있다.
일반적으로 피보나치 수열을 코드를 구현하면 아래와 같다.
def fib_naive(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
fib = fib_naive(n-1) + fib_naive(n-2)
return fib
단순하지만, 시간이 아주 오래 걸리는 것을 확인할 수 있다.
다음은 recursive DP 방법이다. 아래의 코드를 통해 구현할 수 있다.
fib_array = [0, 1] # F(0)과 F(1) 저장
def fib_recur_dp(n):
if n < len(fib_array): # 찾고자하는 수열이 존재할 때
return fib_array[n] # array에서 값 리턴
else: # 존재하지 않으면
fib = fib_recur_dp(n-1) + fib_recur_dp(n-2) # recursive하게 계산
fib_array.append(fib) # 솔루션을 배열에 저장
return fib
일반적으로 피보나치 수열을 구현했을 때보다 속도가 빠른 것을 확인할 수 있다. 하지만 recursive DP에는 치명적인 단점이 존재한다. 너무 큰 숫자는 스택에 저장되는 양이 많아지면 오버플로우가 발생할 수 있다. 이를 해결하기 위해 bottom-up DP 방법을 사용하면된다
bottom-up DP? subproblem으로 쪼개나가는 것이 아닌, 가장 작은 subproblem의 F(0)부터 F(1), F(2) 순서대로 채워 나가는 것을 의미한다.
F(0) | F(1) | F(2) | F(3) | ... |
이렇게 채워나가면 반복문을 통해 채워나갈 수 있다. bottom-up 코드의 예시를 확인해보자.
def fib_dp(n):
if n == 0:
return 0
else n == 1:
return 1
fib_array = [0, 1]
for i in range(2, n+1): # 2에서 n까지 array를 채워나감
num = fib_array[i-1] + fib_array[i-2] # 솔루션을 제시
fib_array.append(num) # 이 솔루션을 array에 추가
return fib_array[i] # n번째 element를 반환
위의 코드는 시간 복잡도도 O(n)이며 공간 복잡도도 O(n)인것을 확인할 수 있다. 공간복잡도는 데이터를 지워줄 수 있다면 O(1)까지 내려가는 것을 확인할 수 있다.
★ 제일 중요한 것은 problem과 subproblem 정의를 찾아낼 수 있는 것이다. 이는 많은 유형의 문제를 경험해야 터득할 수 있는 부분이다.
'Algorithm > Algorithms & Data Structure' 카테고리의 다른 글
[Algorithm] Greedy (0) | 2022.10.27 |
---|---|
[Algorithm] 백트래킹(Backtracking) (0) | 2022.10.25 |
[Algorithm] DFS/BFS (0) | 2022.07.12 |
[Algorithm] 이진 탐색 (0) | 2022.06.29 |
[Algorithm] Knapsack Problem (0) | 2022.06.22 |