PAITS Cheat Sheet Algorithms Intermediate Updated 2026-10-23

Dynamic Programming Patterns & State Transition Equations

0/1 & Unbounded Knapsack, LCS/Edit Distance, Interval DP, Bitmask DP, and space-reduction templates.

Executive Summary: Systematic taxonomy of Dynamic Programming (DP) archetypes with recurrence relations, iteration-order invariants, and rolling-array space optimizations from O(N*W) down to O(W).

Key Equations & Invariants

0/1 Knapsack Recurrence (1D Space-Optimized)
dp[w] = \max\bigl(dp[w],\; dp[w - \text{weight}_i] + \text{val}_i\bigr) \quad \text{for } w = W \text{ down to } \text{weight}_i

Iterating capacity w backwards prevents using the same item multiple times in the same step.

Levenshtein Edit Distance
dp[i][j] = \begin{cases} dp[i-1][j-1] & s_1[i]=s_2[j] \\ 1 + \min(dp[i-1][j],\, dp[i][j-1],\, dp[i-1][j-1]) & \text{otherwise} \end{cases}

Models minimum insertions, deletions, and substitutions to transform s_1 into s_2.

1. Five Core DP Archetypes & Iteration Orders

Every DP formulation requires three components: (1) minimal state variables that satisfy the Markov property, (2) base cases, and (3) a topological evaluation order over the state DAG.

ArchetypeState DefinitionLoop DirectionClassic Problems
0/1 Knapsackdp[w] = max value with capacity wOuter: items; Inner: w from W down to wt[i]Subset Sum, Partition Equal Subset
Unbounded Knapsackdp[w] = min/max ways for capacity wOuter: items; Inner: w from wt[i] up to WCoin Change, Rod Cutting
Two-Sequence Alignmentdp[i][j] on prefixes A[:i], B[:j]i from 1..m, j from 1..n (rolling 2 rows)LCS, Edit Distance, Regex Match
Interval DPdp[i][j] on subarray s[i..j]Length len from 2..n; left i from 0..n-lenMatrix Chain Multiplication, Burst Balloons
Bitmask DPdp[mask][u] over visited subset maskmask from 0..(1<<n)-1Traveling Salesperson (TSP) in O(n^2 2^n)
1D Space-Optimized 0/1 Knapsack vs Unbounded Coin Changepython
def knapsack_01(weights: list[int], values: list[int], capacity: int) -> int:
    dp = [0] * (capacity + 1)
    for wt, val in zip(weights, values):
        for w in range(capacity, wt - 1, -1):  # Reverse prevents reuse
            dp[w] = max(dp[w], dp[w - wt] + val)
    return dp[capacity]

def min_coins_unbounded(coins: list[int], amount: int) -> int:
    INF = amount + 1
    dp = [0] + [INF] * amount
    for c in coins:
        for a in range(c, amount + 1):  # Forward allows unlimited reuse
            dp[a] = min(dp[a], dp[a - c] + 1)
    return dp[amount] if dp[amount] < INF else -1

Common Production & Interview Pitfalls

Frequently Asked Questions

Q: When is top-down memoization faster than bottom-up tabulation?

When the state space is sparse and only a small fraction of all possible states are reachable from the initial query, top-down memoization skips unreachable states entirely.