Open In App

Grid Unique Paths – Count Paths in matrix

Last Updated : 06 Nov, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

Given an matrix of size m x n, the task is to find the count of all unique possible paths from top left to the bottom right with the constraints that from each cell we can either move only to the right or down.

Examples: 

Input: m = 2, n = 2
Output: 2
Explanation: There are two paths
(0, 0) -> (0, 1) -> (1, 1)
(0, 0) -> (1, 0) -> (1, 1)

Input: m = 2, n = 3
Output: 3
Explanation: There are three paths
(0, 0) -> (0, 1) -> (0, 2) -> (1, 2)
(0, 0) -> (0, 1) -> (1, 1) -> (1, 2)
(0, 0) -> (1, 0) -> (1, 1) -> (1, 2)

Using Recursion – O(2^(n+m)) Time and O(n+m) Space

We can recursively move either to the right or down from the start until we reach the destination and then adding up all valid paths to get the answer. A person can reach from cell (i, j) to (i+1, j) or (i, j+1). Thus for each cell (i, j) we can calculate the number of ways to reach destination by adding up both value. This gives us the following recurrence relation:

  • numberOfPaths(i, j) = numberOfPaths(i+1, j) + numberOfPaths(i, j+1)
C++
// A  c++ program to count all possible paths
// from top left to bottom right
// using recursion

#include <iostream>
using namespace std;

int numberOfPaths(int m, int n) {

    // If either given row number is first or given column
    // number is first
    if (m == 1 || n == 1)
        return 1;

    //  sum the paths coming from the cell above (m-1, n)
    // and the cell to the left (m, n-1)
    return numberOfPaths(m - 1, n) + numberOfPaths(m, n - 1);
}

int main() {
    int m = 3;
    int n = 3;
    int res = numberOfPaths(m, n);
    cout << res << endl;
    return 0;
}
Java
// A Java program to count all possible paths
// from top left to bottom right
// using recursion

class GfG {

    static int numberOfPaths(int m, int n) {

        // If either given row number is first or
        // given column number is first
        if (m == 1 || n == 1)
            return 1;

        return numberOfPaths(m - 1, n)
            + numberOfPaths(m, n - 1);
    }

    public static void main(String args[]) {
        int m = 3;
        int n = 3;
        int res = numberOfPaths(m, n);
        System.out.println(res);
    }
}
Python
# Python program to count all possible paths
# from top left to bottom right
# using recursion


def numberOfPaths(m, n):

    # If either given row number is first
    # or given column number is first
    if(m == 1 or n == 1):
        return 1

    return numberOfPaths(m - 1, n) + numberOfPaths(m, n - 1)


if __name__ == '__main__':
    m = 3
    n = 3
    res = numberOfPaths(m, n)
    print(res)
C#
// A C# program to count all possible paths
// from top left to bottom right
// using recursion

using System;

class GfG {

    static int numberOfPaths(int m, int n) {

        // If either given row number is first or
        // given column number is first
        if (m == 1 || n == 1)
            return 1;

        return numberOfPaths(m - 1, n)
            + numberOfPaths(m, n - 1);
    }

    static public void Main() {
        int m = 3;
        int n = 3;
        int res = numberOfPaths(m, n);
        Console.WriteLine(res);
    }
}
JavaScript
// A Javascript program to count all possible paths
// from top left to bottom right
// using recursion

function numberOfPaths(m, n) {

    // If either given row number is first or
    // given column number is first
    if (m == 1 || n == 1)
        return 1;

    return numberOfPaths(m - 1, n)
           + numberOfPaths(m, n - 1);
}
m = 3;
n = 3;
res = numberOfPaths(m, n);
console.log(res);

Output
6

Using Top-Down DP (Memoization) – O(m*n) Time and O(m*n) Space

If we notice carefully, we can observe that the above recursive solution holds the following two properties of Dynamic Programming:

1. Optimal Substructure:

Number of unique possibe path to reach cell (n,m) depends on the optimal solutions of the subproblems numberOfPaths(n, m-1) and numberOfPaths(n-1, m). By combining these optimal substrutures, we can efficiently calculate the total number of ways to reach the (n, m)th cell.

2. Overlapping Subproblems:

While applying a recursive approach in this problem, we notice that certain subproblems are computed multiple times. For example, when calculating numberOfPaths(3, 3), we recursively calculate numberOfPaths(3, 2) and numberOfPaths(2, 3), which in turn will recursively compute numberOfPaths(2, 2) again from numberOfPaths(3, 2) and numberOfPaths(2, 3). This redundancy leads to overlapping subproblems.

The recursive solution involves changing two parameters:  m which is representing the current row and n which is representing the current column. We need to track both parameter, so we need to create 2D array of size (m+1) x (n+1). because the m will be in range of [0,m] and n will be in range of [0,n].

C++
// C++ implementation to count of possible paths to reach
// using Top-Down DP (Memoization)

#include <iostream>
#include <vector>
using namespace std;

int countPaths(int m, int n, vector<vector<int>> &memo) {

    // base case
    if (n == 1 || m == 1)
        return memo[m][n] = 1;

    // Add the element in the memo table
    // If it was not computed before
    if (memo[m][n] == 0)
        memo[m][n] = countPaths(m - 1, n, memo) + 
      				countPaths(m, n - 1, memo);

    return memo[m][n];
}

int numberOfPaths(int m, int n) {
    vector<vector<int>> memo(m + 1, vector<int>(n + 1, 0));
    int ans = countPaths(m, n, memo);
    return ans;
}

int main() {
  
    int n = 3, m = 3;
    int res = numberOfPaths(m, n);
    cout << res << endl;
    return 0;
}
Java
// Java implementation to count of possible paths to reach
// using Using Top-Down DP (Memoization)

import java.util.ArrayList;
import java.util.List;

class GfG {

    static int countPaths(int m, int n,
                          List<List<Integer> > memo) {
        if (n == 1 || m == 1) {
            memo.get(m).set(n, 1);
            return 1;
        }

        // Add the element in the memo table
        // If it was not computed before
        if (memo.get(m).get(n) == 0) {
            int paths = countPaths(m - 1, n, memo)
                        + countPaths(m, n - 1, memo);
            memo.get(m).set(n, paths);
        }

        return memo.get(m).get(n);
    }

    static int numberOfPaths(int m, int n) {

        List<List<Integer> > memo = new ArrayList<>();
        for (int i = 0; i <= m; i++) {
            List<Integer> row = new ArrayList<>();
            for (int j = 0; j <= n; j++) {
                row.add(0);
            }
            memo.add(row);
        }

        int res = countPaths(m, n, memo);
        return res;
    }

    public static void main(String[] args) {
        int n = 3, m = 3;

        int ans = numberOfPaths(m, n);

        System.out.println(ans);
    }
}
Python
# Python implementation to count of possible paths to reach
# using Using Top-Down DP (Memoization)

def countPaths(m, n, memo):
    if n == 1 or m == 1:
        memo[m][n] = 1
        return 1

    # Add the element in the memo table
    # If it was not computed before
    if  memo[m][n] == 0:
         memo[m][n] = countPaths(m-1,n, memo) + \
            countPaths(m,n-1, memo)

    return  memo[m][n]


def number_of_paths(m, n):
  	
    memo = [[0 for _ in range(n + 1)] for _ in range(m + 1)]
    ans = countPaths(m, n, memo)
    return ans

if __name__ == "__main__":
    n, m = 3, 3

    res = number_of_paths(m, n)
    print(res)
C#
// C# implementation to count of possible paths to reach
// using Using Top-Down DP (Memoization)

using System;
using System.Collections.Generic;

class GfG {

    static int countPaths(int m, int n,
                          List<List<int> > memo) {
        if (n == 1 || m == 1) {
            memo[m][n] = 1;
            return 1;
        }

        // Add the element in the memo table
        // If it was not computed before
        if (memo[m][n] == 0) {
            memo[m][n] = countPaths(m - 1, n, memo)
                         + countPaths(m, n - 1, memo);
        }

        return memo[m][n];
    }

    static int NumberOfPaths(int m, int n) {

        List<List<int> > memo = new List<List<int> >();
        for (int i = 0; i <= m; i++) {
            List<int> row = new List<int>(new int[n + 1]);
            memo.Add(row);
        }
        int ans = countPaths(m, n, memo);
        return ans;
    }

    static void Main() {
        int n = 3, m = 3;

        int res = NumberOfPaths(m, n);
        Console.WriteLine(res);
    }
}
JavaScript
// Javascript implementation to count of possible paths to
// reach using Using Top-Down DP (Memoization)

function countPaths(m, n, memo) {
    if (n === 1 || m === 1) {
        memo[m][n] = 1;
        return 1;
    }

    // Add the element in the memo table
    // If it was not computed before
    if (memo[m][n] === 0) {
        memo[m][n] = countPaths(m - 1, n, memo)
                     + countPaths(m, n - 1, memo);
    }

    return memo[m][n];
}

function numberOfPaths(m, n) {
    const memo = Array.from({length : m + 1},
                            () => Array(n + 1).fill(0));
    const ans = countPaths(m, n, memo);
    return ans;
}

const n = 3;
const m = 3;

const res = numberOfPaths(m, n);
console.log(res);

Output
6

Using Bottom-Up DP (Tabulation) – O(m * n) Time and O(m * n) Space

The approach is similar to the previous one. just instead of breaking down the problem recursively, we iteratively build up the solution by calculating in bottom-up manner. Maintain a dp[][] table such that dp[i][j] stores the count all unique possible paths to reach the cell (i, j).

Base Case:

  • For i =0 and 0 <= j < m , dp[i][j] = 1
  • for j=0 and 0 <=i< n , dp[i][j] = 1

Recursive Case:

  • For i > 1 and j>1 , dp[i][j] = dp[i-1][j] + dp[i][j-1]
C++
// A C++ program to count all possible paths
// from top left to bottom right
// using tabulation

#include <iostream>
#include <vector>
using namespace std;

int numberOfPaths(int m, int n) {

    int dp[m][n];

    // Count of paths to reach any cell in first column is 1
    for (int i = 0; i < m; i++)
        dp[i][0] = 1;

    // Count of paths to reach any cell in first row is 1
    for (int j = 0; j < n; j++)
        dp[0][j] = 1;

    // Calculate count of paths for other cells in
    // bottom-up manner using the recursive solution
    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];
}

int main() {
    int res = numberOfPaths(3, 3);
    cout << res << endl;
    return 0;
}
Java
// A Java program to count all possible paths
// from top left to bottom right
// using tabulation

import java.io.*;

class GfG {

    static int numberOfPaths(int m, int n) {

        int dp[][] = new int[m][n];

        // Count of paths to reach any cell in
        // first column is 1
        for (int i = 0; i < m; i++)
            dp[i][0] = 1;

        // Count of paths to reach any cell in
        // first row is 1
        for (int j = 0; j < n; j++)
            dp[0][j] = 1;

        // Calculate count of paths for other
        // cells in bottom-up manner using
        // the recursive solution
        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];
    }

    public static void main(String args[]) {
        int res = numberOfPaths(3, 3);

        System.out.println(res);
    }
}
Python
# Python3 program to count all possible paths
# from top left to bottom right
#  using tabulation


def numberOfPaths(m, n):

    dp = [[0 for x in range(n)] for y in range(m)]

    # Count of paths to reach any
    # cell in first column is 1
    for i in range(m):
        dp[i][0] = 1

    # Count of paths to reach any
    # cell in first row is 1
    for j in range(n):
        dp[0][j] = 1

    # Calculate count of paths for other
    # cells in bottom-up
    # manner using the recursive solution
    for i in range(1, m):
        for j in range(1, n):
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
    return dp[m - 1][n - 1]


if __name__ == '__main__':
    m = 3
    n = 3
    res = numberOfPaths(m, n)
    print(res)
C#
// A C#  program to count all possible paths
// from top left to bottom right
// using tabulation
using System;

class GfG {

    static int numberOfPaths(int m, int n) {

        int[, ] dp = new int[m, n];

        // Count of paths to reach any cell in
        // first column is 1
        for (int i = 0; i < m; i++)
            dp[i, 0] = 1;

        // Count of paths to reach any cell in
        // first row is 1
        for (int j = 0; j < n; j++)
            dp[0, j] = 1;

        // Calculate count of paths for other
        // cells in bottom-up manner using
        // the recursive solution
        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];
    }

    static void Main() {
        int res = numberOfPaths(3, 3);
        Console.WriteLine(res);
    }
}
JavaScript
// Javascript program to count all possible paths
// from top left to bottom right
//  using tabulation

function numberOfPaths(m, n) {

    var dp = Array(m).fill(0).map(x => Array(n).fill(0));

    // Count of paths to reach any cell in
    // first column is 1
    for (i = 0; i < m; i++)
        dp[i][0] = 1;

    // Count of paths to reach any cell in
    // first row is 1
    for (j = 0; j < n; j++)
        dp[0][j] = 1;

    // Calculate count of paths for other
    // cells in bottom-up manner using
    // the recursive solution
    for (i = 1; i < m; i++) {
        for (j = 1; j < n; j++)
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
    }
    return dp[m - 1][n - 1];
}

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

Output
6

Using Space Optimized DP – O(n*m) Time and O(n) Space

In the previous approach using dynamic programming, we derived a relation between states as follows:

  • dp[i][j] = dp[i-1][j]+dp[i][j-1]

If we observe carefully, we see that to calculate the current state dp[i][j] , we need the previous row dp[i-1][j] value and the current row dp[i][j-1] value. There is no need to store all previous states Instead, we can maintain a single prev array to store values from the previous row, and update its values to represent the current row as we iterate.

  • dp[j] = dp[j] + dp[j-1]

Here, dp[j-1] represents the value of the current row’s previous cell (i.e., the left cell in the current row, dp[i][j-1]), while dp[j] holds the value from the previous row in the same column (i.e., dp[i-1][j] ).

C++
// A C++ program to count all possible paths
// from top left to bottom right
// using space optimised

#include <iostream>
using namespace std;
int numberOfPaths(int m, int n) {

    //  `dp[j]` will represent the number of paths to
    // reach the current cell in the row, with `dp[j]` initialized
    // to 1 as the only path in the first row.
    int dp[n] = {1};
    dp[0] = 1;

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

            // Update dp[j] to include paths from the 
          	// cell directly to the left. dp[j - 1]` is the value of
         	// the current row's previous cell, and `dp[j]` itself stores
          	// the value from the previous row (same column).
            dp[j] += dp[j - 1];
        }
    }

    return dp[n - 1];
}

int main() {
    int res = numberOfPaths(3, 3);
    cout << res << endl;
}
Java
// A Java program to count all possible paths
// from top left to bottom right
// using space optimised
import java.io.*;

class GfG {

    static int numberOfPaths(int m, int n) {
      
        // Create a 1D array to store results of
      	// subproblems
        int[] dp = new int[n];
        dp[0] = 1;

        for (int i = 0; i < m; i++) {
            for (int j = 1; j < n; j++) {
              
            // Update dp[j] to include paths from the 
          	// cell directly to the left. dp[j - 1]` is the value of
         	// the current row's previous cell, and `dp[j]` itself stores
          	// the value from the previous row (same column).
                dp[j] += dp[j - 1];
            }
        }

        return dp[n - 1];
    }

    public static void main(String args[]) {
        int res = numberOfPaths(3, 3);
        System.out.println(res);
    }
}
Python
# A Python program to count all possible paths
# from top left to bottom right
# using space optimised


def numberOfPaths(p, q):

    # Create a 1D array to store
    # results of subproblems
    dp = [1 for i in range(q)]
    for i in range(p - 1):
        for j in range(1, q):
            dp[j] += dp[j - 1]
    return dp[q - 1]


if __name__ == '__main__':
    print(numberOfPaths(3, 3))
C#
// A C# program to count all possible paths
// from top left to bottom right
// using space optimised

using System;

class GfG {

    static int numberOfPaths(int m, int n) {
      
        // Create a 1D array to store
        // results of subproblems
        int[] dp = new int[n];
        dp[0] = 1;

        for (int i = 0; i < m; i++) {
            for (int j = 1; j < n; j++) {
              
           	// Update dp[j] to include paths from the 
          	// cell directly to the left. dp[j - 1]` is the value of
         	// the current row's previous cell, and `dp[j]` itself stores
          	// the value from the previous row (same column).
                dp[j] += dp[j - 1];
            }
        }

        return dp[n - 1];
    }

    public static void Main() {
        int res = numberOfPaths(3, 3);
        Console.Write(res);
    }
}
JavaScript
// A Javascript program to count all possible paths
// from top left to bottom right
// using space optimised
function numberOfPaths(m, n) {

    // Create a 1D array to store results
    // of subproblems
    dp = Array.from({length : n}, (_, i) => 0);
    dp[0] = 1;

    for (i = 0; i < m; i++) {
        for (j = 1; j < n; j++) {
        
             // Update dp[j] to include paths from the 
          	// cell directly to the left. dp[j - 1]` is the value of
         	// the current row's previous cell, and `dp[j]` itself stores
          	// the value from the previous row (same column).
            dp[j] += dp[j - 1];
        }
    }

    return dp[n - 1];
}

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

Output
6

Time Complexity: O(m x n), The program uses nested loops to fill the 1D array “dp”. The outer loop runs “m” times, and the inner loop runs “n” times. Therefore, the time complexity of the program is O(m*n).
Auxiliary Space: O(n), The program uses a 1D array “dp” of size “n” to store the results of subproblems. Hence, the space complexity of the program is O(n).

Note: the count can also be calculated using the formula (m-1 + n-1)!/(m-1)! * (n-1)!

Using combinatorics – O(1) Time and O(1) Space

To solve the problem follow the below idea:

In this combinatorics approach, We have to calculate m+n-2Cn-1 here which will be (m+n-2)! / (n-1)! (m-1)! 
m = number of rows, n = number of columns.

Total number of moves in which we have to move down to reach the last row = m – 1 (m rows, since we are starting from (1, 1) that is not included)
Total number of moves in which we have to move right to reach the last column = n – 1 (n column, since we are starting from (1, 1) that is not included)

Down moves = (m – 1)
Right moves = (n – 1)
Total moves = Down moves + Right moves = (m – 1) + (n – 1) 

Now think of moves as a string of ‘R’ and ‘D’ characters where ‘R’ at any ith index will tell us to move ‘Right’ and ‘D’ will tell us to move ‘Down’. Now think of how many unique strings (moves) we can make where in total there should be (n – 1 + m – 1) characters and there should be (m – 1) ‘D’ character and (n – 1) ‘R’ character? 

Choosing positions of (n – 1) ‘R’ characters results in the automatic choosing of (m – 1) ‘D’ character positions 

The number of ways to choose positions for (n – 1) ‘R’ character = Total positions C n – 1 = Total positions C m – 1 = (n – 1 + m – 1) != [Tex]\frac {(n – 1 + m – 1)!} {(n – 1) ! (m – 1)!}                                   [/Tex] 

Another way to think about this problem: 

Count the Number of ways to make an N digit Binary String (String with 0s and 1s only) with ‘X’ zeros and ‘Y’ ones (here we have replaced ‘R’ with ‘0’ or ‘1’ and ‘D’ with ‘1’ or ‘0’ respectively whichever suits you better) 

C++
// A C++ program to count all possible paths from
// top left to top bottom using combinatorics

#include <iostream>
using namespace std;

int numberOfPaths(int m, int n) {
  
    // We have to calculate m+n-2 C n-1 here
    // which will be (m+n-2)! / (n-1)! (m-1)!
    int path = 1;
    for (int i = n; i < (m + n - 1); i++) {
        path *= i;
        path /= (i - n + 1);
    }
    return path;
}

 
int main() {
  
    int res = numberOfPaths(3, 3);
    cout<< res <<endl;
    return 0;
}
Java
// Java program to count all possible paths from
// top left to top bottom using combinatorics

import java.io.*;

class GfG {

    static int numberOfPaths(int m, int n) {
      
        // We have to calculate m+n-2 C n-1 here
        // which will be (m+n-2)! / (n-1)! (m-1)!
        int path = 1;
        for (int i = n; i < (m + n - 1); i++) {
            path *= i;
            path /= (i - n + 1);
        }
        return path;
    }

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

 
Python
# Python3 program to count all possible
# paths from top left to top bottom
# using combinatorics


def numberOfPaths(m, n):
    path = 1
    # We have to calculate m + n-2 C n-1 here
    # which will be (m + n-2)! / (n-1)! (m-1)! path = 1;
    for i in range(n, (m + n - 1)):
        path *= i
        path //= (i - n + 1)

    return path


 
res = numberOfPaths(3, 3)
print(res)

 
C#
// C# program to count all possible paths from
// top left to top bottom using combinatorics
using System;

class GfG {

    static int numberOfPaths(int m, int n) {
      
        // We have to calculate m+n-2 C n-1 here
        // which will be (m+n-2)! / (n-1)! (m-1)!
        int path = 1;
        for (int i = n; i < (m + n - 1); i++) {
            path *= i;
            path /= (i - n + 1);
        }
        return path;
    }

    
   	static void Main() {
      int res = numberOfPaths(3,3);
        Console.WriteLine(res);
    }
}
JavaScript
// Javascript program to count all possible paths from
// top left to top bottom using combinatorics
function numberOfPaths(m, n){

    // We have to calculate m+n-2 C n-1 here
    // which will be (m+n-2)! / (n-1)! (m-1)!
    var path = 1;
    for (i = n; i < (m + n - 1); i++) {
        path *= i;
        path = parseInt(path / (i - n + 1));
    }
    return path;
}

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

Output
6

Time Complexity: O(m), The time complexity is O(m), where m is the maximum of m and n. This is because the for loop iterates m times, and each iteration involves a constant number of arithmetic operations.
Auxiliary Space: O(1),



Next Article

Similar Reads