Problem
You have a robot sitting at the top-left corner of an mรn grid. The robot can only move right or down. Count how many distinct paths exist from the top-left to the bottom-right corner.
- Input: m = 3, n = 7
- Output: 28
- Explanation: With 3 rows and 7 columns, there are exactly 28 distinct right-down paths from corner to corner.
If m = 3, n = 2 to see a smaller case: every path must take exactly 1 step down and 1 step right (in some order), giving just 3 paths.
Intuition
Every single path from top-left to bottom-right makes exactly (mโ1) down moves and (nโ1) right moves โ the total number of steps is fixed, only the order varies. You can either count directly using combinatorics, or build up the answer cell by cell: the number of paths reaching any cell equals the paths arriving from above plus the paths arriving from the left, since those are the only two ways to enter it.
Approach 1 โ Dynamic Programming
Maintain a single row of counts and update it in-place. Before processing row i, row[j] holds the number of paths to reach row iโ1, column j (from above). After updating left-to-right, row[j] accumulates the left-neighbor's count too, giving the correct total for row i.
- Initialize an array of length n filled with 1s โ every cell in the first row has exactly one path (keep moving right).
- For each subsequent row, leave
row[0]untouched (left column is always 1 โ only path is straight down). - For columns 1 through nโ1, set
row[j] += row[j-1]โ adds left-neighbor paths to the already-stored above-paths. - Repeat for all mโ1 remaining rows.
- Return
row[n-1].
1def uniquePaths(self, m: int, n: int) -> int:
2 row = [1] * n # first row: exactly one path to each cell
3
4 for _ in range(1, m):
5 for col in range(1, n):
6 row[col] += row[col - 1] # row[col] still holds above-count; add left-count
7
8 return row[n - 1]Time: O(m ร n) โ visits every cell exactly once.
Space: O(n) โ one row of counts reused for each of the m rows.
Approach 2 โ Math (Combinatorics)
Every path consists of exactly (mโ1) down steps and (nโ1) right steps, totaling (m+nโ2) moves. Counting distinct paths is identical to choosing which (mโ1) of those moves are the down steps: C(m+nโ2, mโ1).
- Compute total steps:
steps = m + n - 2. - Choose the smaller of (mโ1) and (nโ1) as
kto minimize loop iterations. - Compute C(steps, k) iteratively: multiply by
(steps - i)and divide by(i + 1)at each step to stay integer-valued and avoid overflow. - Return the result.
1from math import comb
2
3def uniquePaths(self, m: int, n: int) -> int:
4 # choose which (m-1) of the (m+n-2) total moves are downward steps
5 return comb(m + n - 2, m - 1)Time: O(min(m, n)) โ loop runs at most min(mโ1, nโ1) iterations.
Space: O(1) โ only a handful of scalar variables.
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| Dynamic Programming | O(m ร n) | O(n) | Default; extends naturally to Unique Paths II with obstacles |
| Math (Combinatorics) | O(min(m, n)) | O(1) | When m and n are very large and no obstacles are present |
Common Mistakes
- Forgetting to initialize the first row to all 1s โ the base case is that every cell in the top row (and left column) has exactly one path; initializing with zeros forces you to fill them separately and is easy to get wrong.
- Starting the inner loop at col = 0 โ
row[0]must stay 1 throughout (left column always has one path), so the update loop must begin at column 1. - Using
factorialfor the combinatorics approach โ computingfactorial(m+n-2) // factorial(m-1) // factorial(n-1)creates a huge intermediate value before dividing; the iterative formulation multiplies and divides in lockstep, keeping the running total small and integer-valued at every step. - Assuming the answer changes when you swap m and n โ C(m+nโ2, mโ1) = C(m+nโ2, nโ1), so the answer is symmetric; swapping rows and columns gives the same count, which is correct mathematically but can mask a bug in problems that extend this grid (like Unique Paths II).
- Applying the math formula when there are blocked cells โ the combinatorics approach counts all orderings of moves, which only works on an empty grid; any obstacle invalidates it and requires the DP approach.
Related Problems
unique-paths-iiโ same grid traversal but with obstacles; forces the DP approachminimum-path-sumโ find the minimum-cost path using the identical cell recurrencetriangleโ similar row-by-row DP on a triangular structureclimbing-stairsโ the 1D version of this recurrence (ways to reach step n)coin-changeโ another classic count-paths-to-target DP problem