150NeetCode 150

111.Unique Paths

MediumBlind 752-D Dynamic Programming · 1/11

Problem

A robot starts in the top-left cell of an m x n grid and wants to reach the bottom-right cell. At every step it may move only right or down.

Return the number of distinct paths the robot can take. The answer is guaranteed to fit in a 32-bit signed integer.

Examples

Input:  m = 3, n = 7
Output: 28
Explanation: Any path consists of 2 downs and 6 rights in some order: C(8, 2) = 28.
Input:  m = 3, n = 2
Output: 3
Explanation: Right→Down→Down, Down→Right→Down, Down→Down→Right.
Input:  m = 1, n = 1
Output: 1
Explanation: The robot is already at the target — the empty path counts.

Constraints

  • 1 <= m, n <= 100
  • The answer is <= 2 * 10^9.

💡 Key Insight

The only ways to arrive at cell (r, c) are from the cell above it or the cell to its left, so paths(r, c) = paths(r - 1, c) + paths(r, c - 1), with every cell in the first row or first column having exactly 1 path. Each row only depends on the previous row, so one 1-D array is enough. Alternatively, every path is an arrangement of m - 1 downs and n - 1 rights, so the answer is the binomial coefficient C(m + n - 2, m - 1).

Recursion (Brute Force)

TimeO(2^(m+n))SpaceO(m + n)

Intuition

Stand at (r, c) and ask "how many ways to the goal from here?". Move right or move down and add the two counts. Walking off the grid gives 0 ways; standing on the goal gives 1 way.

Algorithm

  1. Define count(r, c):
    • If r == m or c == n, return 0 (off the grid).
    • If r == m - 1 and c == n - 1, return 1 (reached the goal).
    • Return count(r + 1, c) + count(r, c + 1).
  2. Return count(0, 0).

Visualization

flowchart TD
    A["(0,0)"] -->|"down"| B["(1,0)"]
    A -->|"right"| C["(0,1)"]
    B -->|"down"| D["(2,0)"]
    B -->|"right"| E["(1,1)"]
    C -->|"down"| F["(1,1) again"]
    C -->|"right"| G["(0,2) off grid → 0"]
    D -->|"right"| H["(2,1) goal → 1"]
    E -->|"down"| I["(2,1) goal → 1"]
    F -->|"down"| J["(2,1) goal → 1"]

For m = 3, n = 2 the three leaves that reach the goal give 3. Notice that (1,1) is solved twice — the overlap explodes on larger grids.

Code

java
class Solution {
    public int uniquePaths(int m, int n) {
        return count(0, 0, m, n);
    }

    private int count(int r, int c, int m, int n) {
        if (r == m || c == n) {
            return 0; // stepped outside the grid
        }
        if (r == m - 1 && c == n - 1) {
            return 1; // reached bottom-right
        }
        return count(r + 1, c, m, n) + count(r, c + 1, m, n);
    }
}

Complexity

  • Time: O(2^(m+n)) — every call branches twice and the path length is m + n - 2.
  • Space: O(m + n) — recursion depth equals the path length.

Complexity Comparison

Approach Time Space
Recursion (Brute Force) O(2^(m+n)) O(m + n)
Top-Down Memoization O(m · n) O(m · n)
Bottom-Up 2-D Tabulation O(m · n) O(m · n)
Space-Optimized 1-D DP O(m · n) O(n)
Combinatorics O(min(m, n)) O(1)

Common Pitfalls

  • Initializing the first row/column to 0 instead of 1 — there is exactly one way to reach each of those cells.
  • Using int in the combinatorics loop: result * (total - k + i) can exceed 2^31 before the division; use long.
  • Dividing before multiplying (result / i * (...)) — the intermediate is not always divisible and truncates.
  • Off-by-one in the binomial: it is C(m + n - 2, m - 1), not C(m + n, m).
  • Forgetting the m == 1 or n == 1 case — the answer is 1, which every approach above handles naturally.