Dynamic Programming solves problems by breaking them into smaller subproblems, solving each subproblem once, and storing results for reuse. It is typically used for optimization problems (e.g., maximizing/minimizing a value) and involves two main approaches:
Below are the major DP patterns, their characteristics, and templates for solving them.
Description: Problems where the state is represented by a single variable (e.g., index or count). Typically involves a single array for storing intermediate results.
Examples:
Memoization Template:
def solve(n):
memo = {}
def dp(i):
if i in memo:
return memo[i]
if i <= base_case_value: # Base case
return base_case_result
memo[i] = transition_function(dp(i-1), dp(i-2), ...) # Recurrence relation
return memo[i]
return dp(n)
Tabulation Template:
def solve(n):
if n <= base_case_value:
return base_case_result
dp = [0] * (n + 1) # Initialize 1D array
dp[0] = base_case_0 # Set base cases
dp[1] = base_case_1
for i in range(2, n + 1):
dp[i] = transition_function(dp[i-1], dp[i-2], ...) # Fill table
return dp[n]
Key Points:
dp[i] represents the solution for the subproblem at index i.dp[i] to previous states (e.g., dp[i] = dp[i-1] + dp[i-2]).