Limited time: AI code review, hints, mock interviews, whiteboard analysis, and all Pro features are unlocked. Enroll
⏱️ 7 min read

Dynamic Programming

The pattern: Break a problem into overlapping subproblems, solve each once, store the result, and reuse it. DP = recursion + memoization (top-down) or iterative table-filling (bottom-up).

Why this matters in interviews: DP is the most-feared interview topic, but it follows predictable patterns. Once you identify the β€œstate” and β€œtransition,” the code writes itself. ~25% of hard-level problems use DP.


When to Recognize It


How It Works

Think of climbing stairs. To reach step 5, you came from step 4 or step 3. To reach step 4, you came from step 3 or step 2. Notice step 3 gets computed twice? DP stores that answer so you only compute it once.

flowchart TD
    A["dp[5] = ?"]:::client
    B["dp[4]"]:::service
    C["dp[3]"]:::service
    D["dp[3]"]:::data
    E["dp[2]"]:::data
    F["dp[2]"]:::data
    G["dp[1]"]:::data

    A --> B
    A --> C
    B --> D
    B --> E
    C --> F
    C --> G

    classDef client fill:#4c3a5e,stroke:#818cf8,color:#e2e8f0
    classDef service fill:#1a3a2a,stroke:#4ade80,color:#e2e8f0
    classDef data fill:#3b3520,stroke:#fbbf24,color:#e2e8f0

The DP framework (4 steps):

  1. Define the state: What does dp[i] (or dp[i][j]) represent?
  2. Find the transition: How does dp[i] relate to smaller states?
  3. Set base cases: What’s the answer for the smallest inputs?
  4. Determine the order: Fill the table so dependencies are computed first.

Template Code

Code

# 1D DP: Climbing Stairs (number of ways to reach step n)
def climb_stairs(n):
    if n <= 2:
        return n
    dp = [0] * (n + 1)
    dp[1], dp[2] = 1, 2

    for i in range(3, n + 1):
        dp[i] = dp[i-1] + dp[i-2]  # transition

    return dp[n]

# Space-optimized (only need last 2 values)
def climb_stairs_opt(n):
    if n <= 2:
        return n
    prev2, prev1 = 1, 2
    for i in range(3, n + 1):
        curr = prev1 + prev2
        prev2, prev1 = prev1, curr
    return prev1
// 1D DP: Climbing Stairs
int climbStairs(int n) {
    if (n <= 2) return n;
    int[] dp = new int[n + 1];
    dp[1] = 1; dp[2] = 2;
    for (int i = 3; i <= n; i++) {
        dp[i] = dp[i-1] + dp[i-2];
    }
    return dp[n];
}

// Space-optimized
int climbStairsOpt(int n) {
    if (n <= 2) return n;
    int prev2 = 1, prev1 = 2;
    for (int i = 3; i <= n; i++) {
        int curr = prev1 + prev2;
        prev2 = prev1;
        prev1 = curr;
    }
    return prev1;
}
// 1D DP: Climbing Stairs
int climbStairs(int n) {
    if (n <= 2) return n;
    vector<int> dp(n + 1);
    dp[1] = 1; dp[2] = 2;
    for (int i = 3; i <= n; i++) {
        dp[i] = dp[i-1] + dp[i-2];
    }
    return dp[n];
}
// 1D DP: Climbing Stairs
function climbStairs(n) {
    if (n <= 2) return n;
    const dp = new Array(n + 1).fill(0);
    dp[1] = 1; dp[2] = 2;
    for (let i = 3; i <= n; i++) {
        dp[i] = dp[i-1] + dp[i-2];
    }
    return dp[n];
}

Variations

2D DP: Longest Common Subsequence (LCS)

dp[i][j] = LCS of text1[0..i-1] and text2[0..j-1].

Code

def longest_common_subsequence(text1, text2):
    m, n = len(text1), len(text2)
    dp = [[0] * (n + 1) for _ in range(m + 1)]

    for i in range(1, m + 1):
        for j in range(1, n + 1):
            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])

    return dp[m][n]
int longestCommonSubsequence(String text1, String text2) {
    int m = text1.length(), n = text2.length();
    int[][] dp = new int[m + 1][n + 1];
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (text1.charAt(i-1) == text2.charAt(j-1))
                dp[i][j] = dp[i-1][j-1] + 1;
            else
                dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
        }
    }
    return dp[m][n];
}
int longestCommonSubsequence(string text1, string text2) {
    int m = text1.size(), n = text2.size();
    vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; 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]);
        }
    }
    return dp[m][n];
}
function longestCommonSubsequence(text1, text2) {
    const m = text1.length, n = text2.length;
    const dp = Array.from({length: m + 1}, () => Array(n + 1).fill(0));
    for (let i = 1; i <= m; i++) {
        for (let j = 1; j <= n; j++) {
            if (text1[i-1] === text2[j-1])
                dp[i][j] = dp[i-1][j-1] + 1;
            else
                dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
        }
    }
    return dp[m][n];
}

0/1 Knapsack

dp[i][w] = max value using first i items with weight capacity w. For each item: take it (dp[i-1][w - weight[i]] + value[i]) or skip it (dp[i-1][w]).

Longest Increasing Subsequence (LIS)

dp[i] = length of LIS ending at index i. For each j < i where nums[j] < nums[i]: dp[i] = max(dp[i], dp[j] + 1).

Optimization: Use patience sorting with binary search for O(n log n).


Complexity

Pattern Time Space
1D DP (climbing stairs, house robber) O(n) O(n) or O(1)
2D DP (LCS, grid paths) O(m * n) O(m * n) or O(n)
0/1 Knapsack O(n * W) O(n * W) or O(W)
LIS (DP) O(nΒ²) O(n)
LIS (binary search) O(n log n) O(n)

Common Mistakes


Practice Problems


Key Takeaways

Free system design + DSA prep. If it helped you crack an interview, consider supporting.

SensAI SensAI
Beta
Listening...
Tap mic to stop voice mode

Shape what we build next

Every piece of feedback is read by the team and directly influences our roadmap.

What type of feedback?

Install SystemCraft

Add to your home screen for instant access, offline reading, and a distraction-free experience.

Offline reading Faster loads No browser tabs App-like feel

Unlock AI Features

One click to activate - no payment, no credit card. Just sign in and you're in.

AI code review and hints
SensAI chat assistant
AI mock interviews
Whiteboard analysis
100% free during early access