π Unique Paths - The Discovery Journey
How the human brain naturally discovers the DP solution
π Unique Paths Series:
- π The Discovery Journey (You are here) - How humans naturally discover the solution
- π΄ Unoptimized Recursive - Pure recursion and exponential complexity
- Plain English Proof - Accessible logical reasoning
- Formal Proof - Mathematical rigor and certainty
- When Reality Gets Messy - Adapting to obstacles
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)
1. Discovery & Problem Understandingβ
1.1 Problem Analysis & 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
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 combinatorics approach works, but let's discover the DP insight that will serve us for hundreds of similar problems.
1.2 Recursive Insight & Pattern Recognitionβ
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)
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?β
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 β
1.3 Critical Prerequisites & Why It Worksβ
The Critical Insight (Prerequisite You Might Be Missing)β
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 (fromi,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:
- Don't overlap (can't simultaneously do both as final move)
- 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)
Why Does paths_to(i,j) = paths_to(i-1,j) + paths_to(i,j-1) Work?β
The formula works because:
- Exhaustiveness: Every path to
(i,j)must come from either(i-1,j)or(i,j-1)- there are no other possibilities - Mutual Exclusivity: A path cannot simultaneously arrive from both directions - the final move is unique
- Independence: The number of ways to reach the two predecessor cells are independent events
This is the fundamental counting principle applied to path problems!
2. Implementation & Optimizationβ
2.1 Recursive Solution (Intuitive but Slow)β
Option 1: Pure 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)
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! π±
Visual: The Recursion Problemβ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 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! π± β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2.2 2D DP Array (Memoization)β
The Coder's Brain: Why This Data Structure?β
Now that we understand the logic, how do we store this?
We already calculated this grid:
1 1 1
1 2 3
1 3 6
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)
Implementation: 2D DP Arrayβ
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];
Visual: 2D DPβ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 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) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2.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!
How In-Place Updating Worksβ
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: 1D Arrayβ
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];
}
- 2D Array: O(m Γ n)
- 1D Array: O(n)
- Same time complexity: O(m Γ n)
Visual: 1D DPβ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 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) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
3. Mastery & Validationβ
3.1 Edge Cases as Concept Validatorsβ
Edge Case 1: 1Γ1 Gridβ
START = END
- Already at destination
- Answer: 1 way (do nothing)
- Tests: Base case handling
Edge Case 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 Case 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 Case 4: Why Can't We Have 0 Paths?β
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.
Test Your Understandingβ
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!
3.2 Meta-Process & Frameworkβ
The Meta-Process (Framework for ALL Problems)β
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
The Pattern Recognitionβ
Trigger: "count paths in grid"
Think: "build each cell from its dependencies"
Template:
// Base cases: edges = 1
// Recurrence: dp[i][j] = sum of predecessor cells
// Fill order: topological (usually leftβright, topβbottom)
Dependency Order Mattersβ
The order in which we fill the grid is critical:
Must fill in topological order:
- Dependencies must be calculated BEFORE dependents
- Usually: left-to-right, top-to-bottom
- Sometimes reversed (Dungeon Game)
3.3 Key Takeaways & Summaryβ
Key Takeawaysβ
-
The Recursive Insight:
paths(i,j) = paths(i-1,j) + paths(i,j-1)- This is the foundation of the entire solution
-
Why Addition Works:
- Mutually exclusive events (can't come from both directions simultaneously)
- Exhaustive (covers all possibilities)
-
Three Implementation Levels:
- Recursion β Simple but slow (O(2^(m+n)))
- 2D DP β Clear and standard (O(mΓn) time, O(mΓn) space)
- 1D DP β Space optimized (O(mΓn) time, O(n) space)
-
The Pattern Recognition:
- When you see "count paths in grid"
- Think: "build each cell from its dependencies"
-
Dependency Order Matters:
- Must fill in topological order
- Usually: left-to-right, top-to-bottom
Visual Summary: The Three Approachesβ
EVOLUTION PATH:
Recursion (Understanding)
β
[Identify repeated work]
β
2D DP (Standard Solution)
β
[Optimize space usage]
β
1D DP (Optimal Solution)
Next Stepsβ
After mastering Unique Paths, try these variations:
- Unique Paths II - Add obstacles
- Minimum Path Sum - Change from counting to optimization
- Dungeon Game - Reverse the direction!
- Triangle - Irregular grid structure
Each builds on the same core insight but adds one new complexity.
You now understand the discovery process that leads to the solution.
This mental model will serve you for hundreds of similar problems - master the recursion first, optimize second! π
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.