Given a grid grid[][] of size n × m containing values 0 and 1 having the following meanings:
0 represents an open cell through which movement is allowed.
1 represents a blocked cell that cannot be traversed.
Starting from the top-left cell (0, 0), find the total number of distinct paths to reach the bottom-right cell (n - 1, m - 1). From any cell, movement is allowed only in the right and down directions, and a path is valid only if it passes through open cells.
Note: It is guaranteed that the answer fits within a 32-bit integer.
Examples:
Input: grid[][] = {{0, 0, 0},{0, 1, 0},{0, 0, 0}} Output: 2 Explanation: There are two distinct paths from (0, 0) to (2, 2) while avoiding the blocked cell.
[Naive Approach] Using Recursion - O(2^(n*m)) Time and O(n+m) Space
The idea is to start from the top-left cell and try all possible ways to reach the bottom-right cell. From any cell, we can move either down or right. We recursively explore both choices and count the number of valid paths. If we reach a blocked cell or go outside the grid, that path is discarded.
Base Cases:
If i == r or j == c: The current position is out of bounds, so there are no paths available. Return 0.
If grid[i][j] == 1: The current cell is an obstacle, so it cannot be used. Return 0.
If i == r-1 and j == c-1: The function has reached the destination, so there is exactly one path. Return 1.
[Better Approach 1] Using Top-Down DP(Memoization) - O(n*m) Time and O(n*m) Space
The recursive solution repeatedly solves the same subproblems.. To avoid this, we use memoization, where the answer for each cell is stored in a DP array. Before computing the number of paths from a cell, we first check if its result is already available in the DP array. If yes, we return the stored value; otherwise, we compute it recursively, store it, and return it. This ensures that each cell is processed only once.
Create a n × m DP array and initialize all cells with -1.
Start recursion from the top-left cell (0, 0).
If the current cell is invalid or blocked, return 0.
If the destination cell is reached, return 1.
If the answer for the current cell is already stored in DP, return it.
Otherwise, recursively compute the paths by moving down and right.
Store the result in DP and return it.
Output
2
[Better Approach 2]Using Bottom-Up DP (Tabulation) – O(n*m) Time and O(n*m) Space
Let dp[i][j] represent the number of valid paths from cell (i, j) to the destination. Since we can move only down or right, the number of paths from a cell is the sum of the paths from the cell below and the cell to its right.
The table is filled in an iterative manner from i = n-1 to i = 1 and j = m-1 to j = 1.
The dynamic programming relation is as follows: dp[i][j] = dp[i+1][j] + dp[i][j+1]
Output
2
[Expected Approach] Using Space Optimized DP – O(m*n) Time and O(n) Space
In previous approach of dynamic programming we have derive the relation between states as given below:
dp[i][j] = dp[i+1][j] + dp[i][j+1]
If we observe that for calculating current dp[i][j] state we only need next row dp[i+1][j] and next cells value. There is no need to store all the next states just one next state is used to compute result.