Count Unique Paths in a Grid (original) (raw)

Given two integers **m and **n representing the number of rows and columns of a grid, respectively, find the number of distinct paths from the top-left cell (0, 0) to the bottom-right cell (m - 1, n - 1). From any cell, you can move only right or down.

**Note: The answer is guaranteed to fit within a 32-bit integer.

**Input: m = 2, n = 3
**Output: 3
**Explanation: There are three distinct paths from the top-left cell to the bottom-right cell.

asas_a

**Input: m = 1, n = 4
**Output: 1
**Explanation: There is only one possible path from the top-left cell to the bottom-right cell.

asx_ax

Table of Content

[Naive Approach] Using Recursion - O(2^(m+n)) Time and O(m+n) Space

The idea is to start from the top-left cell and recursively explore all possible paths to reach the bottom-right cell. From any cell, we can move either down or right. The total number of paths from the current cell is the sum of the paths obtained by making these two moves.

Base Cases:

The recurrence relation will be: **solve(i, j, m, n) = solve(i + 1, j, m, n) + solve(i, j + 1, m, n)

C++ `

#include using namespace std;

int solve(int i, int j, int m, int n) {

// Base case - reached bottom-right cell
if (i == m - 1 && j == n - 1)
    return 1;

// Out of bounds
if (i >= m || j >= n)
    return 0;

// Move down or right
return solve(i + 1, j, m, n) + solve(i, j + 1, m, n);

}

int numberOfPaths(int m, int n) { return solve(0, 0, m, n); }

int main() { int m = 2, n = 3; cout << numberOfPaths(m, n); return 0; }

Java

class GfG {

static int solve(int i, int j, int m, int n) {

    // Base case - reached bottom-right cell
    if (i == m - 1 && j == n - 1)
        return 1;

    // Out of bounds
    if (i >= m || j >= n)
        return 0;

    // Move down or right
    return solve(i + 1, j, m, n)
         + solve(i, j + 1, m, n);
}

static int numberOfPaths(int m, int n) {
    return solve(0, 0, m, n);
}

public static void main(String[] args) {
    int m = 2, n = 3;
    System.out.println(numberOfPaths(m, n));
}

}

Python

def solve(i, j, m, n):

# Base case - reached bottom-right cell
if i == m - 1 and j == n - 1:
    return 1

# Out of bounds
if i >= m or j >= n:
    return 0

# Move down or right
return solve(i + 1, j, m, n) + solve(i, j + 1, m, n)

def numberOfPaths(m, n): return solve(0, 0, m, n)

if name == "main": m, n = 2, 3 print(numberOfPaths(m, n))

C#

using System;

class GFG {

static int solve(int i, int j, int m, int n) {

    // Base case - reached bottom-right cell
    if (i == m - 1 && j == n - 1)
        return 1;

    // Out of bounds
    if (i >= m || j >= n)
        return 0;

    // Move down or right
    return solve(i + 1, j, m, n)
         + solve(i, j + 1, m, n);
}

static int numberOfPaths(int m, int n) {
    return solve(0, 0, m, n);
}

static void Main() {
    int m = 2, n = 3;
    Console.WriteLine(numberOfPaths(m, n));
}

}

JavaScript

function solve(i, j, m, n) {

// Base case - reached bottom-right cell
if (i === m - 1 && j === n - 1)
    return 1;

// Out of bounds
if (i >= m || j >= n)
    return 0;

// Move down or right
return solve(i + 1, j, m, n)
     + solve(i, j + 1, m, n);

}

function numberOfPaths(m, n) { return solve(0, 0, m, n); }

//Driver Code let m = 2, n = 3; console.log(numberOfPaths(m, n));

`

[Better Approach] Using DP - O(m*n) Time and O(n) Space

The above recursive solution has overlapping subproblems and can be optimized using Dynamic Programming.

Since the number of paths to a cell depends only on the cell directly above it and the cell to its left, we do not need to store the entire m × n DP table.

We use a 1D array dp[], where dp[j] stores the number of paths to reach the current cell in the current row. Initially, there is exactly one way to reach every cell in the first row, so the array is initialized with 1s.

Traverse the grid row by row and update the array from left to right:

The recurrence relation is: dp[j] = dp[j] + dp[j - 1]

C++ `

#include using namespace std;

int numberOfPaths(int m, int n) {

// dp[j] stores paths to current cell in the row
int dp[n] = {1};

// Only one way to reach first column
dp[0] = 1; 

for (int i = 0; i < m; i++) {
    for (int j = 1; j < n; j++) {

        // Paths from top (dp[j]) + left (dp[j-1])
        dp[j] += dp[j - 1];
    }
}

// Paths to bottom-right cell
return dp[n - 1];

}

int main() { int res = numberOfPaths(2, 3); cout << res << endl; }

Java

class GFG {

static int numberOfPaths(int m, int n) {

    // dp[j] stores paths to current cell in the row
    int[] dp = new int[n];

    // Only one way to reach first column
    dp[0] = 1;

    for (int i = 0; i < m; i++) {
        for (int j = 1; j < n; j++) {

            // Paths from top (dp[j]) + left (dp[j-1])
            dp[j] += dp[j - 1];
        }
    }

    // Paths to bottom-right cell
    return dp[n - 1];
}

public static void main(String[] args) {
    int res = numberOfPaths(2, 3);
    System.out.println(res);
}

}

Python

def numberOfPaths(m, n):

# dp[j] stores paths to current cell in the row
dp = [0] * n

# Only one way to reach first column
dp[0] = 1

for i in range(m):
    for j in range(1, n):

        # Paths from top (dp[j]) + left (dp[j-1])
        dp[j] += dp[j - 1]

# Paths to bottom-right cell
return dp[n - 1]

if name == "main": res = numberOfPaths(2, 3) print(res)

C#

using System;

class GFG {

static int numberOfPaths(int m, int n) {

    // dp[j] stores paths to current cell in the row
    int[] dp = new int[n];

    // Only one way to reach first column
    dp[0] = 1;

    for (int i = 0; i < m; i++) {
        for (int j = 1; j < n; j++) {

            // Paths from top (dp[j]) + left (dp[j-1])
            dp[j] += dp[j - 1];
        }
    }

    // Paths to bottom-right cell
    return dp[n - 1];
}

static void Main() {
    int res = numberOfPaths(2, 3);
    Console.WriteLine(res);
}

}

JavaScript

function numberOfPaths(m, n) {

// dp[j] stores paths to current cell in the row
let dp = new Array(n).fill(0);

// Only one way to reach first column
dp[0] = 1;

for (let i = 0; i < m; i++) {
    for (let j = 1; j < n; j++) {

        // Paths from top (dp[j]) + left (dp[j-1])
        dp[j] += dp[j - 1];
    }
}

// Paths to bottom-right cell
return dp[n - 1];

}

let res = numberOfPaths(2, 3); console.log(res);

`

[Expected Approach] Using Combinatorics - O(min(m, n)) Time and O(1) Space

Instead of computing paths for every cell, we can directly count the number of valid paths using combinatorics. Every path from the top-left cell to the bottom-right cell consists of a fixed number of right and down moves.

To reach cell (m-1, n-1) from (0, 0):

Therefore, the total number of moves is: (m - 1) + (n - 1) = m + n - 2 .

Each unique path corresponds to a unique arrangement of these moves. So, the problem reduces to choosing positions for either:

Hence, the answer is: C(m + n - 2, m - 1) or equivalently, C(m + n - 2, n - 1)

C++ `

#include using namespace std;

int numberOfPaths(int m, int n) {

// Stores the total number of unique paths
long long paths = 1;

// Total moves needed to reach the destination
int totalMoves = m + n - 2;

// Compute C(totalMoves, r), where r is smaller
// because C(n, r) = C(n, n - r)
int r = min(m - 1, n - 1);

// Calculate the binomial coefficient iteratively
for (int i = 1; i <= r; i++)
{
    paths = paths * (totalMoves - r + i) / i;
}

return (int)paths;

}

int main() { int res = numberOfPaths(2, 3); cout << res << endl; return 0; }

Java

class GFG {

 public static int numberOfPaths(int m, int n) {

    // Stores the total number of unique paths
    long paths = 1;

    // Total moves needed to reach the destination
    int totalMoves = m + n - 2;

    // Compute C(totalMoves, r), where r is smaller
    // because C(n, r) = C(n, n - r)
    int r = Math.min(m - 1, n - 1);

    // Calculate the binomial coefficient iteratively
    for (int i = 1; i <= r; i++) {
        paths = paths * (totalMoves - r + i) / i;
    }

    return (int)paths;
}

public static void main(String[] args) {
    int res = numberOfPaths(2, 3);
    System.out.println(res);
}

}

Python

def numberOfPaths(m, n):

# Stores the total number of unique paths
paths = 1

# Total moves needed to reach the destination
totalMoves = m + n - 2

# Compute C(totalMoves, r), where r is smaller
# because C(n, r) = C(n, n - r)
r = min(m - 1, n - 1)

# Calculate the binomial coefficient iteratively
for i in range(1, r + 1):
    paths = paths * (totalMoves - r + i) // i

return int(paths)

if name == "main": res = numberOfPaths(2, 3) print(res)

C#

using System;

class GFG { static int numberOfPaths(int m, int n) {

    // Stores the total number of unique paths
    long paths = 1;

    // Total moves needed to reach the destination
    int totalMoves = m + n - 2;

    // Compute C(totalMoves, r), where r is smaller
    // because C(n, r) = C(n, n - r)
    int r = Math.Min(m - 1, n - 1);

    // Calculate the binomial coefficient iteratively
    for (int i = 1; i <= r; i++)
    {
        paths = paths * (totalMoves - r + i) / i;
    }

    return (int)paths;
}

static void Main()
{
    int res = numberOfPaths(2, 3);
    Console.WriteLine(res);
}

}

JavaScript

function numberOfPaths(m, n) {

// Stores the total number of unique paths
let paths = 1n;

// Total moves needed to reach the destination
let totalMoves = m + n - 2;

// Compute C(totalMoves, r), where r is smaller
// because C(n, r) = C(n, n - r)
let r = Math.min(m - 1, n - 1);

// Calculate the binomial coefficient iteratively
for (let i = 1; i <= r; i++) {
    paths = paths * BigInt(totalMoves - r + i) / BigInt(i);
}

return Number(paths);

}

// Driver code let res = numberOfPaths(2, 3); console.log(res);

`