Unique paths in a Grid with Obstacles (original) (raw)

Given a grid **grid[][] of size **n × **m containing values 0 and 1 having the following meanings:

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.

sss

**Input: grid[][] = {{1, 0, 1}}
**Output: 0
**Explanation: There is no possible path to reach the end.

Table of Content

[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:

The recurrence relation will be:

//Driver Code Starts #include #include using namespace std;

//Driver Code Ends

// Helper function to find unique paths recursively int uniPathRec(int i, int j, vector<vector>& grid) { int r = grid.size(), c = grid[0].size();

// If out of bounds, return 0
if(i == r || j == c) {
    return 0;
}

// If cell is an obstacle, return 0
if(grid[i][j] == 1) {
    return 0;
}

// If reached the bottom-right cell, return 1
if(i == r-1 && j == c-1) {
    return 1;
}

// Recur for the cell below and the cell to the right
return uniPathRec(i+1, j, grid) +
       uniPathRec(i, j+1, grid);

}

// Function to find unique paths with obstacles int uniquePaths(vector<vector>& grid) { return uniPathRec(0, 0, grid); }

//Driver Code Starts

int main() {

vector<vector<int>> grid = { { 0, 0, 0 },{ 0, 1, 0 },{ 0, 0, 0 }
};

cout << uniquePaths(grid);

}

//Driver Code Ends

Java

//Driver Code Starts public class GFG {

//Driver Code Ends

// Helper function to find unique paths recursively
static int uniPathRec(int i, int j, int[][] grid) {
    int r = grid.length, c = grid[0].length;

    // If out of bounds, return 0
    if (i == r || j == c) {
        return 0;
    }

    // If cell is an obstacle, return 0
    if (grid[i][j] == 1) {
        return 0;
    }

    // If reached the bottom-right cell, return 1
    if (i == r - 1 && j == c - 1) {
        return 1;
    }

    // Recur for the cell below and the cell to the right
    return uniPathRec(i + 1, j, grid) +
           uniPathRec(i, j + 1, grid);
}

// Function to find unique paths with obstacles
static int uniquePaths(int[][] grid) {
    return uniPathRec(0, 0, grid);
}

//Driver Code Starts

public static void main(String[] args) {

    int[][] grid = {
        {0, 0, 0},
        {0, 1, 0},
        {0, 0, 0}
    };

    System.out.println(uniquePaths(grid));
}

}

//Driver Code Ends

Python

Helper function to find unique paths recursively

def uniPathRec(i, j, grid): r, c = len(grid), len(grid[0])

# If out of bounds, return 0
if i == r or j == c:
    return 0

# If cell is an obstacle, return 0
if grid[i][j] == 1:
    return 0

# If reached the bottom-right cell, return 1
if i == r-1 and j == c-1:
    return 1

# Recur for the cell below and the cell to the right
return uniPathRec(i+1, j, grid) + \
       uniPathRec(i, j+1, grid)

Function to find unique paths with obstacles

def uniquePaths(grid): return uniPathRec(0, 0, grid)

#Driver Code Starts

if name == "main": grid = [ [0, 0, 0], [0, 1, 0], [0, 0, 0] ]

print(uniquePaths(grid))

#Driver Code Ends

C#

//Driver Code Starts using System;

class GFG { //Driver Code Ends

// Helper function to find unique paths recursively
static int uniPathRec(int i, int j, int[,] grid)
{
    int r = grid.GetLength(0);
    int c = grid.GetLength(1);

    // If out of bounds, return 0
    if (i == r || j == c)
    {
        return 0;
    }

    // If cell is an obstacle, return 0
    if (grid[i, j] == 1)
    {
        return 0;
    }

    // If reached the bottom-right cell, return 1
    if (i == r - 1 && j == c - 1)
    {
        return 1;
    }

    // Recur for the cell below and the cell to the right
    return uniPathRec(i + 1, j, grid) +
           uniPathRec(i, j + 1, grid);
}

// Function to find unique paths with obstacles
static int uniquePaths(int[,] grid)
{
    return uniPathRec(0, 0, grid);
}

//Driver Code Starts

static void Main(string[] args)
{
    int[,] grid = {
        { 0, 0, 0 },
        { 0, 1, 0 },
        { 0, 0, 0 }
    };

    Console.WriteLine(uniquePaths(grid));
}

}

//Driver Code Ends

JavaScript

// Helper function to find unique paths recursively function uniPathRec(i, j, grid) { let r = grid.length, c = grid[0].length;

// If out of bounds, return 0
if (i === r || j === c) {
    return 0;
}

// If cell is an obstacle, return 0
if (grid[i][j] === 1) {
    return 0;
}

// If reached the bottom-right cell, return 1
if (i === r - 1 && j === c - 1) {
    return 1;
}

// Recur for the cell below and the cell to the right
return uniPathRec(i + 1, j, grid) +
       uniPathRec(i, j + 1, grid);

}

// Function to find unique paths with obstacles function uniquePaths(grid) { return uniPathRec(0, 0, grid); }

//Driver Code Starts // Driver code let grid = [ [0, 0, 0], [0, 1, 0], [0, 0, 0] ];

console.log(uniquePaths(grid));

//Driver Code Ends

`

[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.

//Driver Code Starts #include #include using namespace std; //Driver Code Ends

// Helper function to find unique paths int uniPathRec(int i, int j, vector<vector>& grid, vector<vector>& dp) { int r = grid.size(), c = grid[0].size();

// If out of bounds, return 0
if(i == r || j == c) {
    return 0;
}

// If cell is an obstacle, return 0
if(grid[i][j] == 1) {
    return 0;
}

// If reached the bottom-right cell, return 1
if(i == r-1 && j == c-1) {
    return 1;
}

// If already computed, return the stored result
if(dp[i][j] != -1) {
    return dp[i][j];
}

// Compute and store the result
dp[i][j] = uniPathRec(i+1, j, grid, dp) + 
             uniPathRec(i, j+1, grid, dp);

return dp[i][j];

}

// Function to find unique paths with obstacles int uniquePaths(vector<vector>& grid) { int n = grid.size(), m = grid[0].size();

vector<vector<int>> dp(n, vector<int>(m, -1));

return uniPathRec(0, 0, grid, dp);

}

//Driver Code Starts

int main() { vector<vector> grid = { { 0, 0, 0 }, { 0, 1, 0 }, { 0, 0, 0 } };

cout << uniquePaths(grid);

return 0;

} //Driver Code Ends

Java

//Driver Code Starts import java.util. Arrays;

public class GFG {

//Driver Code Ends

// Helper function to find unique paths
static int uniPathRec(int i, int j, int[][] grid, int[][] dp) {
    int r = grid.length, c = grid[0].length;

    // If out of bounds, return 0
    if (i == r || j == c) {
        return 0;
    }

    // If cell is an obstacle, return 0
    if (grid[i][j] == 1) {
        return 0;
    }

    // If reached the bottom-right cell, return 1
    if (i == r - 1 && j == c - 1) {
        return 1;
    }

    // If already computed, return the stored result
    if (dp[i][j] != -1) {
        return dp[i][j];
    }

    // Compute and store the result
    dp[i][j] = uniPathRec(i + 1, j, grid, dp) +
               uniPathRec(i, j + 1, grid, dp);

    return dp[i][j];
}

// Function to find unique paths with obstacles
static int uniquePaths(int[][] grid) {
    int n = grid.length, m = grid[0].length;

    int[][] dp = new int[n][m];
    for (int[] row : dp) Arrays.fill(row, -1);

    return uniPathRec(0, 0, grid, dp);
}

//Driver Code Starts

public static void main(String[] args) {

    int[][] grid = {
            {0, 0, 0},
            {0, 1, 0},
            {0, 0, 0}
    };

    System.out.println(uniquePaths(grid));
}

}

//Driver Code Ends

Python

Helper function to find unique paths

def uniPathRec(i, j, grid, dp): r, c = len(grid), len(grid[0])

# If out of bounds, return 0
if i == r or j == c:
    return 0

# If cell is an obstacle, return 0
if grid[i][j] == 1:
    return 0

# If reached the bottom-right cell, return 1
if i == r - 1 and j == c - 1:
    return 1

# If already computed, return the stored result
if dp[i][j] != -1:
    return dp[i][j]

# Compute and store the result
dp[i][j] = uniPathRec(i + 1, j, grid, dp) + \
           uniPathRec(i, j + 1, grid, dp)

return dp[i][j]

Function to find unique paths with obstacles

def uniquePaths(grid): n, m = len(grid), len(grid[0]) dp = [[-1] * m for _ in range(n)] return uniPathRec(0, 0, grid, dp)

#Driver Code Starts

if name == "main": grid = [ [0, 0, 0], [0, 1, 0], [0, 0, 0] ]

print(uniquePaths(grid))

#Driver Code Ends

C#

//Driver Code Starts using System; using System.Collections.Generic;

class GFG { //Driver Code Ends

// Helper function to find unique paths
static int uniPathRec(int i, int j, int[,] grid, int[,] dp)
{
    int r = grid.GetLength(0), c = grid.GetLength(1);

    // If out of bounds, return 0
    if (i == r || j == c)
    {
        return 0;
    }

    // If cell is an obstacle, return 0
    if (grid[i, j] == 1)
    {
        return 0;
    }

    // If reached the bottom-right cell, return 1
    if (i == r - 1 && j == c - 1)
    {
        return 1;
    }

    // If already computed, return the stored result
    if (dp[i, j] != -1)
    {
        return dp[i, j];
    }

    // Compute and store the result
    dp[i, j] = uniPathRec(i + 1, j, grid, dp) +
               uniPathRec(i, j + 1, grid, dp);

    return dp[i, j];
}

// Function to find unique paths with obstacles
static int uniquePaths(int[,] grid)
{
    int n = grid.GetLength(0), m = grid.GetLength(1);

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

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            dp[i, j] = -1;
        }
    }

    return uniPathRec(0, 0, grid, dp);
}

//Driver Code Starts

static void Main()
{
    int[,] grid = new int[,]
    {
        {0, 0, 0},
        {0, 1, 0},
        {0, 0, 0}
    };

    Console.WriteLine(uniquePaths(grid));
}

}

//Driver Code Ends

JavaScript

// Helper function to find unique paths function uniPathRec(i, j, grid, dp) { let r = grid.length, c = grid[0].length;

// If out of bounds, return 0
if (i === r || j === c) {
    return 0;
}

// If cell is an obstacle, return 0
if (grid[i][j] === 1) {
    return 0;
}

// If reached the bottom-right cell, return 1
if (i === r - 1 && j === c - 1) {
    return 1;
}

// If already computed, return the stored result
if (dp[i][j] !== -1) {
    return dp[i][j];
}

// Compute and store the result
dp[i][j] = uniPathRec(i + 1, j, grid, dp) +
           uniPathRec(i, j + 1, grid, dp);

return dp[i][j];

}

// Function to find unique paths with obstacles function uniquePaths(grid) { let n = grid.length, m = grid[0].length;

let dp = Array.from({ length: n }, () => Array(m).fill(-1));

return uniPathRec(0, 0, grid, dp);

}

//Driver Code Starts //Driver Code let grid = [ [0, 0, 0], [0, 1, 0], [0, 0, 0] ];

console.log(uniquePaths(grid));

//Driver Code Ends

`

[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.

C++ `

//Driver Code Starts #include #include using namespace std;

//Driver Code Ends

int uniquePaths(vector<vector>& grid) { int n = grid.size(), m = grid[0].size();

// If starting or ending cell is an obstacle, return 0
if(grid[0][0] == 1 || grid[n-1][m-1] == 1) {
    return 0;
}

vector<vector<int>> dp(n, vector<int>(m, 0));
dp[n-1][m-1] = 1;

// Fill the bottom row
for(int j = m-2; j >= 0; j--) {
    
    // As this is an obstacle, no paths will 
    // exist from this cell.
    if(grid[n-1][j] == 1) {
        break;
    }
    
    // Otherwise, a straight path to 
    // n-1, m-1 exists 
    else {
        dp[n-1][j] = 1;
    }
}

// Fill the rightmost column
for(int i = n-2; i >= 0; i--) {
    
    // As this is an obstacle, no paths will 
    // exist from this cell.
    if(grid[i][m-1] == 1) {
        break;
    }
    
    // Otherwise, a straight path to 
    // n-1, m-1 exists 
    else {
        dp[i][m-1] = 1;
    }
}

// Fill the inner cells bottom-up and right-left
for(int i = n-2; i >= 0; i--) {
    for(int j = m-2; j >= 0; j--) {
        if(grid[i][j] == 0) {
            
            // Number of paths = sum of paths from the 
            // cell below and the cell to the right
            dp[i][j] = dp[i+1][j] + dp[i][j+1];
        }
    }
}

return dp[0][0];

}

//Driver Code Starts

int main() { vector<vector> grid = { { 0, 0, 0 }, { 0, 1, 0 }, { 0, 0, 0 } };

cout << uniquePaths(grid);

return 0;

} //Driver Code Ends

Java

//Driver Code Starts import java.util.Arrays;

public class GFG {

//Driver Code Ends

static int uniquePaths(int[][] grid) {
    int n = grid.length, m = grid[0].length;

    // If starting or ending cell is an obstacle, return 0
    if(grid[0][0] == 1 || grid[n-1][m-1] == 1) {
        return 0;
    }

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

    // Fill the bottom row
    for(int j = m-2; j >= 0; j--) {

        // As this is an obstacle, no paths will 
        // exist from this cell.
        if(grid[n-1][j] == 1) {
            break;
        }

        // Otherwise, a straight path to 
        // n-1, m-1 exists 
        else {
            dp[n-1][j] = 1;
        }
    }

    // Fill the rightmost column
    for(int i = n-2; i >= 0; i--) {

        // As this is an obstacle, no paths will 
        // exist from this cell.
        if(grid[i][m-1] == 1) {
            break;
        }

        // Otherwise, a straight path to 
        // n-1, m-1 exists 
        else {
            dp[i][m-1] = 1;
        }
    }

    // Fill the inner cells bottom-up and right-left
    for(int i = n-2; i >= 0; i--) {
        for(int j = m-2; j >= 0; j--) {
            if(grid[i][j] == 0) {

                // Number of paths = sum of paths from the 
                // cell below and the cell to the right
                dp[i][j] = dp[i+1][j] + dp[i][j+1];
            }
        }
    }

    return dp[0][0];
}

//Driver Code Starts

public static void main(String[] args) {

    int[][] grid = {
        {0, 0, 0},
        {0, 1, 0},
        {0, 0, 0}
    };

    System.out.println(uniquePaths(grid));
}

}

//Driver Code Ends

Python

def uniquePaths(grid): n, m = len(grid), len(grid[0])

# If starting or ending cell is an obstacle, return 0
if grid[0][0] == 1 or grid[n-1][m-1] == 1:
    return 0

dp = [[0] * m for _ in range(n)]
dp[n-1][m-1] = 1

# Fill the bottom row
for j in range(m-2, -1, -1):

    # As this is an obstacle, no paths will 
    # exist from this cell.
    if grid[n-1][j] == 1:
        break

    # Otherwise, a straight path to 
    # n-1, m-1 exists 
    else:
        dp[n-1][j] = 1

# Fill the rightmost column
for i in range(n-2, -1, -1):

    # As this is an obstacle, no paths will 
    # exist from this cell.
    if grid[i][m-1] == 1:
        break

    # Otherwise, a straight path to 
    # n-1, m-1 exists 
    else:
        dp[i][m-1] = 1

# Fill the inner cells bottom-up and right-left
for i in range(n-2, -1, -1):
    for j in range(m-2, -1, -1):
        if grid[i][j] == 0:

            # Number of paths = sum of paths from the 
            # cell below and the cell to the right
            dp[i][j] = dp[i+1][j] + dp[i][j+1]

return dp[0][0]

//Driver Code Starts

if name == "main": grid = [ [0, 0, 0], [0, 1, 0], [0, 0, 0] ]

print(uniquePaths(grid))

//Driver Code Ends

C#

//Driver Code Starts using System;

class GFG { //Driver Code Ends

static int uniquePaths(int[,] grid)
{
    int n = grid.GetLength(0), m = grid.GetLength(1);

    // If starting or ending cell is an obstacle, return 0
    if (grid[0,0] == 1 || grid[n-1,m-1] == 1)
    {
        return 0;
    }

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

    // Fill the bottom row
    for (int j = m - 2; j >= 0; j--)
    {
        // As this is an obstacle, no paths will 
        // exist from this cell.
        if (grid[n-1, j] == 1) break;

        // Otherwise, a straight path to 
        // n-1, m-1 exists 
        dp[n-1, j] = 1;
    }

    // Fill the rightmost column
    for (int i = n - 2; i >= 0; i--)
    {
        // As this is an obstacle, no paths will 
        // exist from this cell.
        if (grid[i, m-1] == 1) break;

        // Otherwise, a straight path to 
        // n-1, m-1 exists 
        dp[i, m-1] = 1;
    }

    // Fill the inner cells bottom-up and right-left
    for (int i = n - 2; i >= 0; i--)
    {
        for (int j = m - 2; j >= 0; j--)
        {
            if (grid[i, j] == 0)
            {
                // Number of paths = sum of paths from the 
                // cell below and the cell to the right
                dp[i, j] = dp[i+1, j] + dp[i, j+1];
            }
        }
    }

    return dp[0, 0];
}

//Driver Code Starts

static void Main()
{
    int[,] grid = new int[,]
    {
        {0, 0, 0},
        {0, 1, 0},
        {0, 0, 0}
    };

    Console.WriteLine(uniquePaths(grid));
}

}

//Driver Code Ends

JavaScript

function uniquePaths(grid) { let n = grid.length, m = grid[0].length;

// If starting or ending cell is an obstacle, return 0
if (grid[0][0] === 1 || grid[n-1][m-1] === 1) {
    return 0;
}

let dp = Array.from({ length: n }, () => Array(m).fill(0));
dp[n-1][m-1] = 1;

// Fill the bottom row
for (let j = m - 2; j >= 0; j--) {

    // As this is an obstacle, no paths will 
    // exist from this cell.
    if (grid[n-1][j] === 1) break;

    // Otherwise, a straight path to 
    // n-1, m-1 exists 
    dp[n-1][j] = 1;
}

// Fill the rightmost column
for (let i = n - 2; i >= 0; i--) {

    // As this is an obstacle, no paths will 
    // exist from this cell.
    if (grid[i][m-1] === 1) break;

    // Otherwise, a straight path to 
    // n-1, m-1 exists 
    dp[i][m-1] = 1;
}

// Fill the inner cells bottom-up and right-left
for (let i = n - 2; i >= 0; i--) {
    for (let j = m - 2; j >= 0; j--) {
        if (grid[i][j] === 0) {

            // Number of paths = sum of paths from the 
            // cell below and the cell to the right
            dp[i][j] = dp[i+1][j] + dp[i][j+1];
        }
    }
}

return dp[0][0];

}

//Driver Code Starts //Driver Code let grid = [ [0, 0, 0], [0, 1, 0], [0, 0, 0] ];

console.log(uniquePaths(grid));

//Driver Code Ends

`

[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:

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.

C++ `

//Driver Code Starts #include #include using namespace std;

//Driver Code Ends

int uniquePaths(vector<vector>& grid) { int n = grid.size(), m = grid[0].size();

// If starting or ending cell is an obstacle, return 0
if(grid[0][0] == 1 || grid[n-1][m-1] == 1) {
    return 0;
}

vector<int> dp(m, 0);

dp[m-1] = 1;

// Fill the bottom row first
for(int j = m-2; j >= 0; j--) {
    
    // As this is an obstacle, no paths will 
    // exist from this cell.
    if(grid[n-1][j] == 1) {
        dp[j] = 0;
    }
    
    // Otherwise, a straight path to 
    // n-1, m-1 exists 
    else {
        dp[j] = dp[j+1];
    }
}

// Process each row from bottom to top
for(int i = n-2; i >= 0; i--) {
    
    // Process the rightmost column of the current row
    if(grid[i][m-1] == 1) {
        dp[m-1] = 0;
    }
    
    // Process each cell from right to left
    for(int j = m-2; j >= 0; j--) {
        
        // If current cell is an obstacle, paths = 0
        if(grid[i][j] == 1) {
            dp[j] = 0;
        }
        
        // Otherwise, paths = sum of right and down paths
        else {
            dp[j] = dp[j] + dp[j+1];
        }
    }
}

return dp[0];

}

//Driver Code Starts

int main() { vector<vector> grid = { { 0, 0, 0 }, { 0, 1, 0 }, { 0, 0, 0 } };

cout << uniquePaths(grid);

return 0;

} //Driver Code Ends

Java

//Driver Code Starts import java.util.Arrays;

public class GFG {

//Driver Code Ends

static int uniquePaths(int[][] grid) {
    int n = grid.length, m = grid[0].length;
    
    // If starting or ending cell is an obstacle, return 0
    if(grid[0][0] == 1 || grid[n-1][m-1] == 1) {
        return 0;
    }

    int[] dp = new int[m];

    dp[m-1] = 1;
    
    // Fill the bottom row first
    for(int j = m-2; j >= 0; j--) {
        
        // As this is an obstacle, no paths will 
        // exist from this cell.
        if(grid[n-1][j] == 1) {
            dp[j] = 0;
        }
        
        // Otherwise, a straight path to 
        // n-1, m-1 exists 
        else {
            dp[j] = dp[j+1];
        }
    }
    
    // Process each row from bottom to top
    for(int i = n-2; i >= 0; i--) {
        
        // Process the rightmost column of the current row
        if(grid[i][m-1] == 1) {
            dp[m-1] = 0;
        }
        
        // Process each cell from right to left
        for(int j = m-2; j >= 0; j--) {
            
            // If current cell is an obstacle, paths = 0
            if(grid[i][j] == 1) {
                dp[j] = 0;
            }
            
            // Otherwise, paths = sum of right and down paths
            else {
                dp[j] = dp[j] + dp[j+1];
            }
        }
    }
    
    return dp[0];
}

//Driver Code Starts

public static void main(String[] args) {
    int[][] grid = {
        { 0, 0, 0 },
        { 0, 1, 0 },
        { 0, 0, 0 }
    };

    System.out.println(uniquePaths(grid));
}

}

//Driver Code Ends

Python

def uniquePaths(grid): n = len(grid) m = len(grid[0])

# If starting or ending cell is an obstacle, return 0
if grid[0][0] == 1 or grid[n-1][m-1] == 1:
    return 0

dp = [0] * m

dp[m-1] = 1

# Fill the bottom row first
for j in range(m-2, -1, -1):
    
    # As this is an obstacle, no paths will 
    # exist from this cell.
    if grid[n-1][j] == 1:
        dp[j] = 0
    
    # Otherwise, a straight path to 
    # n-1, m-1 exists 
    else:
        dp[j] = dp[j+1]

# Process each row from bottom to top
for i in range(n-2, -1, -1):
    
    # Process the rightmost column of the current row
    if grid[i][m-1] == 1:
        dp[m-1] = 0
    
    # Process each cell from right to left
    for j in range(m-2, -1, -1):
        
        # If current cell is an obstacle, paths = 0
        if grid[i][j] == 1:
            dp[j] = 0
        
        # Otherwise, paths = sum of right and down paths
        else:
            dp[j] = dp[j] + dp[j+1]

return dp[0]

#Driver Code Starts if name == "main": grid = [ [0,0,0], [0,1,0], [0,0,0] ]

print(uniquePaths(grid))

#Driver Code Ends

C#

//Driver Code Starts using System;

public class GFG {

//Driver Code Ends

public static int uniquePaths(int[,] grid) {
    int n = grid.GetLength(0), m = grid.GetLength(1);
    
    // If starting or ending cell is an obstacle, return 0
    if(grid[0,0] == 1 || grid[n-1, m-1] == 1) {
        return 0;
    }

    int[] dp = new int[m];

    dp[m-1] = 1;
    
    // Fill the bottom row first
    for(int j = m-2; j >= 0; j--) {
        
        // As this is an obstacle, no paths will 
        // exist from this cell.
        if(grid[n-1, j] == 1) {
            dp[j] = 0;
        }
        
        // Otherwise, a straight path to 
        // n-1, m-1 exists 
        else {
            dp[j] = dp[j+1];
        }
    }
    
    // Process each row from bottom to top
    for(int i = n-2; i >= 0; i--) {
        
        // Process the rightmost column of the current row
        if(grid[i, m-1] == 1) {
            dp[m-1] = 0;
        }
        
        // Process each cell from right to left
        for(int j = m-2; j >= 0; j--) {
            
            // If current cell is an obstacle, paths = 0
            if(grid[i, j] == 1) {
                dp[j] = 0;
            }
            
            // Otherwise, paths = sum of right and down paths
            else {
                dp[j] = dp[j] + dp[j+1];
            }
        }
    }
    
    return dp[0];
}

//Driver Code Starts

public static void Main() {
    int[,] grid = {
        { 0, 0, 0 },
        { 0, 1, 0 },
        { 0, 0, 0 }
    };
    
    Console.WriteLine(uniquePaths(grid));
}

}

//Driver Code Ends

JavaScript

function uniquePaths(grid) { let n = grid.length, m = grid[0].length;

// If starting or ending cell is an obstacle, return 0
if (grid[0][0] === 1 || grid[n-1][m-1] === 1) {
    return 0;
}

let dp = Array(m).fill(0);

dp[m-1] = 1;

// Fill the bottom row first
for (let j = m-2; j >= 0; j--) {
    
    // As this is an obstacle, no paths will 
    // exist from this cell.
    if (grid[n-1][j] === 1) {
        dp[j] = 0;
    }
    
    // Otherwise, a straight path to 
    // n-1, m-1 exists 
    else {
        dp[j] = dp[j+1];
    }
}

// Process each row from bottom to top
for (let i = n-2; i >= 0; i--) {
    
    // Process the rightmost column of the current row
    if (grid[i][m-1] === 1) {
        dp[m-1] = 0;
    }
    
    // Process each cell from right to left
    for (let j = m-2; j >= 0; j--) {
        
        // If current cell is an obstacle, paths = 0
        if (grid[i][j] === 1) {
            dp[j] = 0;
        }
        
        // Otherwise, paths = sum of right and down paths
        else {
            dp[j] = dp[j] + dp[j+1];
        }
    }
}

return dp[0];

}

//Driver Code Starts //Driver Code let grid = [ [0,0,0], [0,1,0], [0,0,0] ];

console.log(uniquePaths(grid));

//Driver Code Ends

`