Skip to main content

๐Ÿ“˜ Unique Paths - The Discovery Journey

How the human brain naturally discovers the DP solution

SERIES NAVIGATION

๐Ÿ“˜ Unique Paths Series:

  1. ๐Ÿ“˜ The Discovery Journey (You are here) - How humans naturally discover the solution
  2. Plain English Proof - Accessible logical reasoning
  3. Formal Proof - Mathematical rigor and certainty
  4. When Reality Gets Messy - Adapting to obstacles
THE PROBLEM (LC 62)

A robot is located at the top-left corner of an m ร— n grid. The robot can only move either down or right at any point in time.

Goal: How many possible unique paths are there to reach the bottom-right corner?

Example: 3ร—3 grid โ†’ 6 unique paths

Constraints: All cells are reachable (no obstacles)


๐Ÿง  The Designer's Brain: The Messy Discovery Processโ€‹

First Thought: "What if I just try all paths?"โ€‹

You're at the top-left corner of a 3ร—3 grid. You can only move right or down. Let's trace this out:

START (0,0)
โ”œโ”€ Go RIGHT to (0,1)
โ”‚ โ”œโ”€ Go RIGHT to (0,2)
โ”‚ โ”‚ โ””โ”€ Go DOWN to (1,2)
โ”‚ โ”‚ โ””โ”€ Go DOWN to (2,2) โœ“ END
โ”‚ โ”‚
โ”‚ โ””โ”€ Go DOWN to (1,1)
โ”‚ โ”œโ”€ Go RIGHT to (1,2)
โ”‚ โ”‚ โ””โ”€ Go DOWN to (2,2) โœ“ END
โ”‚ โ””โ”€ Go DOWN to (2,1)
โ”‚ โ””โ”€ Go RIGHT to (2,2) โœ“ END
โ”‚
โ””โ”€ Go DOWN to (1,0)
โ”œโ”€ Go RIGHT to (1,1)
โ”‚ โ”œโ”€ Go RIGHT to (1,2)
โ”‚ โ”‚ โ””โ”€ Go DOWN to (2,2) โœ“ END
โ”‚ โ””โ”€ Go DOWN to (2,1)
โ”‚ โ””โ”€ Go RIGHT to (2,2) โœ“ END
โ”‚
โ””โ”€ Go DOWN to (2,0)
โ””โ”€ Go RIGHT to (2,1)
โ””โ”€ Go RIGHT to (2,2) โœ“ END
THE PATTERN EMERGES

Every path is a sequence of decisions. For a 3ร—3 grid, you need:

  • 2 moves RIGHT (R)
  • 2 moves DOWN (D)
  • Total: 4 moves

Wait... this is just asking: "In how many ways can I arrange 2 R's and 2 D's?"

RRDD
RDRD
RDDR
DRRD
DRDR
DDRR

That's 6 ways. Combinatorics: C(4,2) = 6.


๐Ÿค” But Wait... Let's Not Jump to Combinatorics Yetโ€‹

The Recursive Insight (Usually the First Instinct)โ€‹

Standing at any cell, I ask: "How many ways to reach the END from HERE?"

If I'm at cell (i,j):

  • I can come from the cell ABOVE me (i-1, j)
  • I can come from the cell to my LEFT (i, j-1)
CRITICAL INSIGHT #1
paths_to(i,j) = paths_to(i-1,j) + paths_to(i,j-1)

Why addition? Because these are mutually exclusive events:

  • Paths coming from above are DIFFERENT from paths coming from left
  • No path can simultaneously come from both directions

๐Ÿ“Š Let's Trace This on a 3ร—3 Gridโ€‹

I'll mark each cell with "how many ways to reach it from START (0,0)":

START
โ†“
1 โ†’ 1 โ†’ 1
โ†“ โ†“ โ†“
1 โ†’ 2 โ†’ 3
โ†“ โ†“ โ†“
1 โ†’ 3 โ†’ 6
โ†‘
END

Why These Numbers?โ€‹

STEP-BY-STEP REASONING

Top row: Only ONE way (keep going right)

1 โ†’ 1 โ†’ 1

Left column: Only ONE way (keep going down)

1
โ†“
1
โ†“
1

Cell (1,1): Can come from:

  • (0,1) which has 1 way
  • (1,0) which has 1 way
  • Total: 1 + 1 = 2 ways

Cell (1,2): Can come from:

  • (0,2) which has 1 way
  • (1,1) which has 2 ways
  • Total: 1 + 2 = 3 ways

Cell (2,1): Can come from:

  • (1,1) which has 2 ways
  • (2,0) which has 1 way
  • Total: 2 + 1 = 3 ways

Cell (2,2) - THE END: Can come from:

  • (1,2) which has 3 ways
  • (2,1) which has 3 ways
  • Total: 3 + 3 = 6 ways โœ“

๐Ÿ’ก The Critical Insight (Prerequisite You Might Be Missing)โ€‹

Why Does paths_to(i,j) = paths_to(i-1,j) + paths_to(i,j-1) Work?โ€‹

DEEP UNDERSTANDING REQUIRED

Property 1: Every path must make a FINAL MOVE

  • You can't teleport to (i,j)
  • Your last step was either DOWN (from i-1,j) or RIGHT (from i,j-1)

Property 2: Partition Principle

ALL paths to (i,j) can be split into two groups:

  • Group A: Those whose final move was DOWN
  • Group B: Those whose final move was RIGHT

These groups:

  1. Don't overlap (can't simultaneously do both as final move)
  2. Cover ALL possibilities (must come from somewhere)

Property 3: Bijection (One-to-One Mapping)

  • Every path ending at (i-1,j) can be extended by one DOWN move to reach (i,j)
  • Every path ending at (i,j-1) can be extended by one RIGHT move to reach (i,j)
  • This creates a perfect correspondence

Therefore:

Total paths to (i,j) = |Group A| + |Group B|
= paths_to(i-1,j) + paths_to(i,j-1)

๐Ÿ’ป The Coder's Brain: Why This Data Structure?โ€‹

Now that we understand the logic, how do we store this?

Option 1: Recursion (Mirrors Our Thought Process)โ€‹

function paths(i, j):
if i == 0 or j == 0:
return 1 // base case: edges
return paths(i-1, j) + paths(i, j-1)
PROBLEM: REPEATED CALCULATIONS

We recalculate the same cells many times!

paths(2,2) calls paths(1,2) and paths(2,1)
paths(1,2) calls paths(0,2) and paths(1,1)
paths(2,1) calls paths(1,1) and paths(2,0)
โ†‘
calculated TWICE!

This creates an exponential time complexity! ๐Ÿ˜ฑ


Option 2: 2D Array (Memoization of Recursion)โ€‹

We already calculated this grid:

1  1  1
1 2 3
1 3 6
WHY A 2D ARRAY?

Because our state has TWO dimensions (row, column).

Each unique (i,j) pair needs one storage slot.

The filling order matters:

  • We need (i-1,j) and (i,j-1) BEFORE we can fill (i,j)
  • So fill left-to-right, top-to-bottom (like reading a book)
int[][] dp = new int[m][n];

// Base case: first row and column
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;

// Fill the grid
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}

return dp[m-1][n-1];

Option 3: 1D Array (Space Optimization)โ€‹

KEY OBSERVATION

To fill row i, we only need row i-1.

Previous row: [1, 2, 3]
Current row: [1, ?, ?]

To fill current[1]:

  • Need previous[1] = 2 (from above)
  • Need current[0] = 1 (from left)
  • Result: 1 + 2 = 3

Even better: We can overwrite the array in-place!

Start:    [1, 1, 1]  // represents row 0

After updating position 1:
[1, 2, 1] // position 1 now represents row 1

After updating position 2:
[1, 2, 3] // completed row 1

Full Implementation:

public int uniquePaths(int m, int n) {
int[] dp = new int[n];
Arrays.fill(dp, 1); // first row: all 1s

for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[j] = dp[j] + dp[j-1];
// โ†‘ โ†‘
// from above from left
}
}

return dp[n-1];
}
SPACE COMPLEXITY
  • 2D Array: O(m ร— n)
  • 1D Array: O(n)
  • Same time complexity: O(m ร— n)

๐Ÿšจ Edge Cases as Concept Validatorsโ€‹

Edge 1: 1ร—1 Gridโ€‹

START = END
  • Already at destination
  • Answer: 1 way (do nothing)
  • Tests: Base case handling

Edge 2: 1ร—n Grid (Single Row)โ€‹

START โ†’ โ†’ โ†’ โ†’ END
  • Only one path (keep going right)
  • Answer: 1
  • Tests: Do we handle the "only right moves" case?

Edge 3: mร—1 Grid (Single Column)โ€‹

START
โ†“
โ†“
โ†“
END
  • Only one path (keep going down)
  • Answer: 1
  • Tests: Do we handle the "only down moves" case?

Edge 4: Why Can't We Have 0 Paths?โ€‹

FUNDAMENTAL CONSTRAINT

As long as m โ‰ฅ 1 and n โ‰ฅ 1, there's ALWAYS at least one path.

The grid's connectivity guarantees this.

Validates: Our understanding of the problem constraints.


๐ŸŽฏ The Meta-Process (Framework for ALL Problems)โ€‹

SYSTEMATIC PROBLEM-SOLVING APPROACH

Step 1: Start with the simplest possible approach

"What if I just try everything?" โ†’ Recursion

Step 2: Find the pattern in the recursion

  • Draw it out for small cases
  • Look for repeated work

Step 3: Identify the state

  • What information do I need to know? โ†’ (row, column)
  • How many dimensions? โ†’ 2D problem โ†’ 2D array

Step 4: Find dependencies

  • What do I need to calculate X? โ†’ Dependency graph
  • This determines filling order

Step 5: Optimize storage

  • Do I need ALL previous states? โ†’ Only previous row
  • Can I reuse memory? โ†’ 1D array

๐Ÿ“ Visual Summary: The Three Approachesโ€‹

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ RECURSION (Intuitive but Slow) โ”‚
โ”‚ โ”‚
โ”‚ paths(2,2) โ”‚
โ”‚ โ”œโ”€ paths(1,2) โ”‚
โ”‚ โ”‚ โ”œโ”€ paths(0,2) = 1 โ”‚
โ”‚ โ”‚ โ””โ”€ paths(1,1) โ† REPEATED! โ”‚
โ”‚ โ”‚ โ”œโ”€ paths(0,1) = 1 โ”‚
โ”‚ โ”‚ โ””โ”€ paths(1,0) = 1 โ”‚
โ”‚ โ””โ”€ paths(2,1) โ”‚
โ”‚ โ”œโ”€ paths(1,1) โ† REPEATED! โ”‚
โ”‚ โ””โ”€ paths(2,0) = 1 โ”‚
โ”‚ โ”‚
โ”‚ Time: O(2^(m+n)) - EXPONENTIAL! ๐Ÿ˜ฑ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 2D DP (Clear and Standard) โ”‚
โ”‚ โ”‚
โ”‚ 0 1 2 โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ” โ”‚
โ”‚ 0 โ”‚ 1 โ”‚ 1 โ”‚ 1 โ”‚ โ”‚
โ”‚ โ”œโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ค โ”‚
โ”‚ 1 โ”‚ 1 โ”‚ 2 โ”‚ 3 โ”‚ โ”‚
โ”‚ โ”œโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ค โ”‚
โ”‚ 2 โ”‚ 1 โ”‚ 3 โ”‚ 6 โ”‚ โ† Answer โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ”‚
โ”‚ Time: O(mร—n) Space: O(mร—n) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 1D DP (Space Optimized) โ”‚
โ”‚ โ”‚
โ”‚ Initial: [1, 1, 1] โ”‚
โ”‚ After i=1: [1, 2, 3] โ”‚
โ”‚ After i=2: [1, 3, 6] โ† Answer at dp[2] โ”‚
โ”‚ โ”‚
โ”‚ Time: O(mร—n) Space: O(n) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿงช Test Your Understandingโ€‹

VERIFY YOUR COMPREHENSION

Question 1: In a 4ร—4 grid, how many ways to reach cell (2,2)?

Hint: Build the grid up to that point:

1  1  1  1
1 2 3 4
1 3 ? ?
Click for answer
Cell (2,2) = dp[1][2] + dp[2][1]
= 3 + 3
= 6 ways

Full grid:

1  1  1  1
1 2 3 4
1 3 6 10

Question 2: Why can't we fill the grid in reverse (bottom-right to top-left)?

Hint: Think about dependencies.

Click for answer

Each cell (i,j) depends on (i-1,j) and (i,j-1) (cells above and to the left).

If we start from bottom-right, we'd need values that haven't been calculated yet!

Exception: We COULD do reverse if we reversed the dependencies (using cells below and right), which is what Dungeon Game does.


Question 3: What if the robot could ALSO move diagonally? How does our formula change?

Hint: How many ways can you now enter cell (i,j)?

Click for answer
dp[i][j] = dp[i-1][j]     // from top
+ dp[i][j-1] // from left
+ dp[i-1][j-1]; // from diagonal

Now each cell has 3 incoming paths instead of 2!

For a 3ร—3 grid with diagonal moves:

1  1  1
1 3 5
1 5 13

The center cell (1,1) now has 3 ways instead of 2!


๐ŸŽ“ Key Takeawaysโ€‹

WHAT YOU SHOULD REMEMBER
  1. The Recursive Insight:

    • paths(i,j) = paths(i-1,j) + paths(i,j-1)
    • This is the foundation of the entire solution
  2. Why Addition Works:

    • Mutually exclusive events (can't come from both directions simultaneously)
    • Exhaustive (covers all possibilities)
  3. Three Implementation Levels:

    • Recursion โ†’ Simple but slow
    • 2D DP โ†’ Clear and standard
    • 1D DP โ†’ Space optimized
  4. The Pattern Recognition:

    • When you see "count paths in grid"
    • Think: "build each cell from its dependencies"
  5. Dependency Order Matters:

    • Must fill in topological order
    • Usually: left-to-right, top-to-bottom

๐Ÿš€ Next Stepsโ€‹

After mastering Unique Paths, try these variations:

  1. Unique Paths II - Add obstacles
  2. Minimum Path Sum - Change from counting to optimization
  3. Dungeon Game - Reverse the direction!
  4. Triangle - Irregular grid structure

Each builds on the same core insight but adds one new complexity.


Remember: The best problem solvers don't just memorize solutions. They understand the discovery process that leads to the solution. This mental model will serve you for hundreds of similar problems.