Identify overlapping subproblems, define states cleanly, and convert recursion into efficient
tabulated solutions.
0 / 6 topics completed
0%
00
Introduction to Dynamic Programming
Dynamic Programming (DP) is an optimization technique for problems that
have two key properties: optimal substructure (the optimal solution to a
problem can be built from optimal solutions of its subproblems) and
overlapping subproblems (the same subproblems are solved repeatedly in a
naive recursive solution).
💡
The core DP workflow is always the same three steps: write the brute-force
recursion first, identify which calls repeat and add memoization
(top-down caching), then convert to tabulation (bottom-up, iterative)
for the best performance and to eliminate stack overhead.
Plain Recursion
Re-solves same statesOften exponential time
Memoization (Top-Down)
Cache results by stateRecursion + cache = O(states)
Tabulation (Bottom-Up)
Iterative, fills a tableNo call stack overhead
How to Identify a DP State
Ask:"What changes between recursive calls?"
Ask:"What's the minimum info needed to describe a subproblem?"
Result:Those changing variables become your DP state — usually an index plus 1-2 constraints
01
0/1 Knapsack
Given n items with weights and values, and a knapsack of capacity
W, choose a subset of items maximizing total value without exceeding
W. Each item can be picked at most once (hence "0/1" — take
it or leave it).
Identifying the State
State:dp[i][w] = max value using first i items with capacity w
intunboundedKnapsack(vector<int>&wt, vector<int>&val, intW, intn) {
vector<int>dp(W+1, 0);
for (intw = 1; w <= W; w++) {
for (inti = 0; i < n; i++) {
if (wt[i] <= w) {
dp[w] = max(dp[w], val[i] + dp[w - wt[i]]);
}
}
}
returndp[W];
}
03
Longest Increasing Subsequence (LIS)
Given an array, find the length of the longest subsequence (not necessarily contiguous)
where every element is strictly greater than the previous one.
🚀
O(N log N) Optimization: Maintain a tails array where tails[k] = smallest possible tail value of an increasing subsequence of length k+1. For each new number, binary search for its position in tails and replace it. The length of tails at the end is the LIS length.
Given two strings, find the length of their longest common subsequence. A subsequence is formed by deleting some characters without changing the order of remaining characters.
Identifying the State
State:dp[i][j] = LCS of string A[0..i-1] and string B[0..j-1]
No Match:If A[i-1] != B[j-1]: dp[i][j] = max(dp[i-1][j], dp[i][j-1])
Python
deflongest_common_subsequence(text1, text2):
n, m = len(text1), len(text2)
dp = [[0] * (m + 1) for _ inrange(n + 1)]
foriinrange(1, n + 1):
forjinrange(1, m + 1):
iftext1[i-1] == text2[j-1]:
dp[i][j] = dp[i-1][j-1] + 1else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
returndp[n][m]
C++
intlongestCommonSubsequence(stringtext1, text2) {
intn = text1.length(), m = text2.length();
vector<vector<int>>dp(n + 1, vector<int>(m + 1, 0));
for (inti = 1; i <= n; i++) {
for (intj = 1; j <= m; j++) {
if (text1[i-1] == text2[j-1]) {
dp[i][j] = dp[i-1][j-1] + 1;
} else {
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
}
returndp[n][m];
}
05
Tree DP
Dynamic Programming on Trees involves traversing the tree (usually using DFS) and solving the subproblems defined at each node based on the solutions of its children.
🌳
Common Pattern: At node `u`, compute an answer assuming `u` is included in the solution, and compute another answer assuming `u` is excluded. Return both to the parent.
06
Digit DP
Digit DP is used for problems that ask for the count or sum of numbers in a given range [L, R] that satisfy a specific property (e.g., sum of digits is a prime number).
Standard State Template
Parameters:dp(idx, tight, sum)
idx:Current position from left to right
tight:Boolean. If true, the upper bound for the current digit is limited by the original number.
✨
Practice Exercises
1. Climbing Stairs
You are climbing a staircase. It takes n steps to reach the top. Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
Hint: This is perfectly equivalent to the Fibonacci sequence. The number of ways to reach step i is the sum of ways to reach step i-1 and step i-2.
Python
defclimbStairs(n):
ifn <= 2: returnna, b = 1, 2for_inrange(3, n + 1):
a, b = b, a + breturnb
2. House Robber
You are a professional robber planning to rob houses along a street. You cannot rob adjacent houses. Given an integer array nums representing the money in each house, return the maximum amount of money you can rob.
Hint: For each house i, you either rob it (money[i] + max from i-2) or skip it (max from i-1).