소프트웨어/알고리즘
동적 계획법 - 4. DP 실전 연습 (문제 풀이)
개발_노트
2025. 2. 24. 15:27
4. DP 실전 연습 (문제 풀이)
동적 계획법(DP)의 개념을 이해했다면, 직접 문제를 풀어보는 것이 중요합니다.
이번 장에서는 단계별 난이도의 문제를 통해 DP를 연습하고, 알고리즘 문제 풀이 사이트에서 추천 문제를 선정하여 실력을 향상시키는 방법을 소개합니다.
4-1. 단계별 난이도 문제 풀이
📌 기초 문제 (Basic)
1️⃣ 피보나치 수열 (Fibonacci Numbers)
- 시간 제한: 1초
- 메모리 제한: 128MB
- 공간 복잡도: O(1)
- 문제: n번째 피보나치 수를 구하는 문제
- 접근 방법:
- 재귀 (O(2^n)) → 비효율적
- 메모이제이션 (O(n)) → 최적화
- 바텀업 (O(n), O(1) 메모리) → 최적화
def fib(n):
if not isinstance(n, int) or n < 0:
raise ValueError("n must be a non-negative integer")
if n <= 1:
return n
a, b = 0, 1
for _ in range(2, n + 1):
a, b = b, a + b
return b
# 테스트 케이스
print(fib(10)) # 출력: 55
print(fib(0)) # 출력: 0
print(fib(1)) # 출력: 1
# 예외 처리 테스트
try:
fib(-1)
except ValueError as e:
print(f"Error: {e}") # 출력: ValueError (음수 입력)
2️⃣ 계단 오르기 (Climbing Stairs)
- 시간 제한: 1초
- 메모리 제한: 128MB
- 공간 복잡도: O(1)
- 문제: 한 번에 1칸 또는 2칸씩 올라갈 수 있을 때, n개의 계단을 오르는 방법의 수
- 점화식: dp(n)=dp(n−1)+dp(n−2)
def climb_stairs(n):
if not isinstance(n, int) or n < 0:
raise ValueError("n must be a non-negative integer")
if n <= 2:
return n
a, b = 1, 2
for _ in range(3, n + 1):
a, b = b, a + b
return b
print(climb_stairs(5)) # 출력: 8
print(climb_stairs(10)) # 출력: 89
📌 중급 문제 (Intermediate)
3️⃣ 배낭 문제 (0/1 Knapsack Problem)
- 시간 제한: 2초
- 메모리 제한: 256MB
- 공간 복잡도: O(W) (1D 최적화 적용 가능)
def knapsack(weights, values, W):
if len(weights) != len(values):
raise ValueError("Weights and values must have the same length")
if not all(isinstance(w, int) and w >= 0 for w in weights):
raise ValueError("All weights must be non-negative integers")
if not all(isinstance(v, int) and v >= 0 for v in values):
raise ValueError("All values must be non-negative integers")
if not isinstance(W, int) or W < 0:
raise ValueError("Weight capacity must be a non-negative integer")
n = len(weights)
dp = [0] * (W + 1)
for i in range(n):
for w in range(W, weights[i] - 1, -1):
dp[w] = max(dp[w], dp[w - weights[i]] + values[i])
return dp[W]
# 테스트 케이스
weights = [2, 3, 4, 5]
values = [3, 4, 5, 6]
W = 5
print(knapsack(weights, values, W)) # 출력: 7
4️⃣ 최장 공통 부분 수열 (LCS, Longest Common Subsequence)
- 시간 제한: 2초
- 메모리 제한: 256MB
- 공간 복잡도: O(n×m)
def lcs(s1, s2):
if not isinstance(s1, str) or not isinstance(s2, str):
raise TypeError("Input must be strings")
if not s1 or not s2:
return 0
m, n = len(s1), len(s2)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if s1[i - 1] == s2[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
return dp[m][n]
# 테스트 케이스
print(lcs("abcde", "ace")) # 출력: 3 ("ace")
print(lcs("abc", "def")) # 출력: 0 (공통 부분 수열 없음)
# 예외 처리 테스트
try:
lcs(123, "abc")
except TypeError as e:
print(f"Error: {e}") # 출력: TypeError (문자열이 아님)
4-2. 알고리즘 사이트에서 추천 문제 풀기
📌 백준(Baekjoon) - DP 관련 문제
- 기초: 1003(피보나치 함수), 9095(1, 2, 3 더하기)
- 중급: 12865(평범한 배낭), 11053(가장 긴 증가하는 부분 수열)
- 고급: 9251(LCS), 11049(행렬 곱셈 순서)
👉 사이트: https://www.acmicpc.net/problemset
📌 LeetCode - DP 문제
- Easy: Climbing Stairs (70), House Robber (198)
- Medium: Longest Palindromic Substring (5), Decode Ways (91)
- Hard: Regular Expression Matching (10), Edit Distance (72)
👉 사이트: https://leetcode.com/problemset/dynamic-programming/
📌 프로그래머스 - 코딩테스트 대비 DP 문제
- Level 2: N으로 표현, 타일 장식물
- Level 3: 정수 삼각형, 등굣길
👉 사이트: https://programmers.co.kr/learn/challenges