Skip to content
ΣDSA Patterns
Menu
Language

Pattern #23

Two-Dimensional DP

Essential

State depends on two changing indices (grid, two strings, two pointers in DP).

When to use

Paths in a grid, edit distance, LCS, or any recurrence with two parameters i and j.

Recognition cues

  • Unique paths / min path sum
  • Edit distance / LCS
  • dp[i][j] from neighbors

Common pitfalls

  • Wrong base row/column initialization
  • Iterating in an order that reads unfilled cells
  • Confusing inclusive lengths vs indices

90-second recognition drill

Which pattern fits best?

  • Unique paths / min path sum
  • Edit distance / LCS
  • dp[i][j] from neighbors

Interactive

Mental model

A full worked walkthrough of the invariant. Pause, scrub the dots, or use ← →. Aim to narrate each step yourself.

Step 1 of 8
1
1
1
1
?
?
1
?
?

dp[r][c]=up+left

Unique paths on a 3x3 grid. Borders are 1.

How to think about it

dp[i][j] = answer for a subproblem on prefix i and j (or cell (i,j)). Fill by increasing i+j or scanning rows. Often the answer sits at dp[m][n] or dp[m-1][n-1].

Template shapes

Shape Core move Notes
Grid paths from top/left Obstacles zero out
String DP match → diag+1 else min/max of skips
Rolling array Keep prev row only Save space

Complexity baseline

O(m·n) time and space (or O(min(m,n)) space with rolling).

From template to problem

  1. Define dp[i][j] in words.
  2. Initialize first row/col.
  3. Transition from the geometric neighbors of the recurrence.
  4. Return the corner cell.

Template

Same skeleton in TypeScript, Python, and C#. Adapt the invariant; keep the structure.

Two-Dimensional DP · Template
/** 2D DP template: unique paths (right/down only). dp[c] rolled per row. */
export function uniquePaths(m: number, n: number): number {
  const dp = new Array<number>(n).fill(1);
  for (let r = 1; r < m; r++) {
    for (let c = 1; c < n; c++) dp[c] = dp[c]! + dp[c - 1]!;
  }
  return dp[n - 1]!;
}
/** 2D DP template: unique paths (right/down only). dp[c] rolled per row. */
export function uniquePaths(m: number, n: number): number {
  const dp = new Array<number>(n).fill(1);
  for (let r = 1; r < m; r++) {
    for (let c = 1; c < n; c++) dp[c] = dp[c]! + dp[c - 1]!;
  }
  return dp[n - 1]!;
}
#StatusProblemTypeDone
  1. 1#62 Unique PathsGuide
  2. 2#63 Unique Paths IIGuide
  3. 3#64 Minimum Path SumGuide
  4. 4#72 Edit DistanceGuide
  5. 5#221 Maximal SquareGuide
  6. 6#1143 Longest Common SubsequenceGuide