Knowledge / Computer Science and Engineering / Dynamic programming

Dynamic programming

Computer Science and Engineering (B.E./B.Tech) · Algorithms · free study notes for exams, placements and interviews

In short

Dynamic programming (DP) solves a problem by breaking it into overlapping subproblems, solving each subproblem once, and storing the result so it is never recomputed. It applies when a problem has optimal substructure (an optimal solution is built from optimal solutions of subproblems) and overlapping subproblems (the same subproblem recurs many times) — the two conditions that separate DP from plain divide and conquer. In Indian university courses it is the core of "Design and Analysis of Algorithms" (AICTE model curriculum / UGC CBCS), and in GATE CS it is examined as an algorithm design technique with named problems such as LCS, subset sum, 0/1 knapsack and matrix chain multiplication. In placements it is the highest-weight topic after arrays and graphs: Amazon, Microsoft India, Google India, Flipkart, Walmart Global Tech, Goldman Sachs, Zoho, Oracle, Adobe and the service companies' advanced tracks (TCS NQT Digital, Infosys HackWithInfy) all set DP questions in online rounds and on-site interviews.

Explained

What makes a problem a DP problem

Top-down memoisation versus bottom-up tabulation

Top-down memoisationBottom-up tabulation
CodeClosest to the recurrence; quick to writeNeeds an explicit fill order
States computedOnly the reachable onesAll of them
OverheadFunction-call and hash/array lookupNone
Stack riskRecursion depth (Python default limit ≈1000)No stack use
Space optimisationHardEasy (rolling rows, 1-D arrays)
Best forSparse state space, contest speedTight limits, interviews, exams

How to design a DP in five steps

  1. Define the state in words: dp[i][w] = maximum value using the first i items with capacity w. If it cannot be said in one sentence, the state is wrong.
  2. Write the transition (recurrence): enumerate every decision at that state and combine with min / max / sum.
  3. Fix the base cases, including the empty case and the impossible case (use −∞ for an infeasible maximum, +∞ for an infeasible minimum, 0 for "no ways").
  4. Decide the evaluation order (top-down, or bottom-up over the dependency order) and where the answer sits.
  5. Reconstruct the solution if asked: either store a parent/choice table, or walk the DP table backwards comparing values (no extra memory).
  6. Time = (number of states) × (work per transition); space = number of states, reduced if only the last few rows are needed.

The standard DP families (classification)

Classical recurrences in the syllabus

Complexity, space optimisation and advanced techniques

Advantages, limitations and comparison

Key points

Formulas and examples

Fibonacci: F(n) = F(n−1) + F(n−2), F(0)=0, F(1)=1 — O(n) time, O(1) space with two variables
0/1 knapsack: K[i][w] = max( K[i−1][w], v\_i + K[i−1][w − w\_i] ) if w\_i ≤ w, else K[i−1][w]; K[0][w]=0. v = value (₹), w = weight (kg), W = capacity
Unbounded knapsack / coin change (min coins): C[a] = 1 + min over coins c ≤ a of C[a − c]; C[0] = 0, C[a] = ∞ if unreachable
Coin change (number of ways): W[c][a] = W[c−1][a] + W[c][a − denom\_c]; W[·][0] = 1
LCS: L[i][j] = 1 + L[i−1][j−1] if x\_i = y\_j, else max( L[i−1][j], L[i][j−1] ); L[0][j] = L[i][0] = 0
Edit distance: D[i][j] = min( D[i−1][j] + 1 (delete), D[i][j−1] + 1 (insert), D[i−1][j−1] + cost ), cost = 0 if x\_i = y\_j else 1
Matrix chain multiplication: m[i][j] = min over i ≤ k < j of ( m[i][k] + m[k+1][j] + p\_(i−1)·p\_k·p\_j ); m[i][i] = 0, dimensions A\_i is p\_(i−1) × p\_i
Optimal BST: c[i][j] = min over i ≤ r ≤ j of ( c[i][r−1] + c[r+1][j] ) + Σ(freq i..j)
LIS: dp[i] = 1 + max( dp[j] : j < i and a[j] < a[i] ), answer = max dp[i]
Subset sum: S[i][t] = S[i−1][t] OR S[i−1][t − a\_i]; S[0][0] = true
Rod cutting: r[n] = max over 1 ≤ i ≤ n of ( p[i] + r[n−i] ); p[i] = price (₹) of a piece of length i
TSP (bitmask): dp[mask][i] = min over j ∈ mask, j ≠ i of ( dp[mask \ {i}][j] + cost[j][i] )

Example 1 — 0/1 knapsack (₹ values, kg weights), capacity W = 8 kg. Items: (2 kg, ₹3), (3 kg, ₹4), (4 kg, ₹5), (5 kg, ₹6) — values in thousands of rupees.

i (items considered)w=012345678
0000000000
1 (2,3)003333333
2 (3,4)003447777
3 (4,5)003457899
4 (5,6)0034578910

Example 2 — LCS of X = "ABCBDAB" and Y = "BDCAB".

−BDCAB
−000000
A000011
B011112
C011222
B011223
D012223
A012233
B012234

Example 3 — Matrix chain multiplication. A₁ (5×4), A₂ (4×6), A₃ (6×2), A₄ (2×7); p = [5, 4, 6, 2, 7].

Example 4 — coin change, both variants.

Example 5 — LIS of [10, 22, 9, 33, 21, 50, 41, 60, 80].

# 0/1 knapsack, O(nW) time, O(W) space. Capacity loop runs DOWNWARD.
def knapsack(wt, val, W):
    dp = [0] * (W + 1)
    for i in range(len(wt)):
        for w in range(W, wt[i] - 1, -1):
            dp[w] = max(dp[w], val[i] + dp[w - wt[i]])
    return dp[W]

# Memoisation pattern (top-down). lru_cache replaces a hand-written dict.
from functools import lru_cache
def lcs(x, y):
    @lru_cache(maxsize=None)
    def f(i, j):
        if i == 0 or j == 0: return 0
        if x[i-1] == y[j-1]: return 1 + f(i-1, j-1)
        return max(f(i-1, j), f(i, j-1))
    return f(len(x), len(y))
ProblemStateTimeSpace (optimised)
Fibonacci / stairsiO(n)O(1)
0/1 knapsack, subset sum(i, capacity)O(nW)O(W)
Coin change (unbounded)amountO(n·A)O(A)
LCS, edit distance(i, j)O(mn)O(min(m,n))
MCM, OBST(i, j) + split kO(n³)O(n²)
LISiO(n²) or O(n log n)O(n)
TSP (bitmask)(subset, last city)O(n²·2ⁿ)O(n·2ⁿ)

Where it is used

Interview questions

Common mistakes

Related topics

Open in the Knowledge reader →Find jobs →