Same question just with Obstacles in the grid.
Refer: Space optimization
Recursive Solution
TC: O(2^(m + n)) — This is because each recursive call has two choices, leading to an exponential time complexity.
SC: O(m + n) for the recursion stack.
public class UniquePathsII {
public int uniquePathsWithObstacles ( int [][] obstacleGrid ) {
// If the starting point or ending point has an obstacle, no path is possible.
if (obstacleGrid[ 0 ][ 0 ] == 1 || obstacleGrid[obstacleGrid.length - 1 ][obstacleGrid[ 0 ].length - 1 ] == 1 ) {
return 0 ;
}
return findPaths (obstacleGrid, 0 , 0 );
}
// Recursive function to find paths.
private int findPaths ( int [][] grid , int row , int col ) {
// If we are out of bounds or hit an obstacle, return 0 (no path).
if (row >= grid.length || col >= grid[ 0 ].length || grid[row][col] == 1 ) {
return 0 ;
}
// If we reach the bottom-right corner, there's one valid path.
if (row == grid.length - 1 && col == grid[ 0 ].length - 1 ) {
return 1 ;
}
// Explore the path by moving down and right.
int downPaths = findPaths (grid, row + 1 , col);
int rightPaths = findPaths (grid, row, col + 1 );
// Total paths are the sum of the paths from down and right directions.
return downPaths + rightPaths;
}
public static void main ( String [] args ) {
UniquePathsII solution = new UniquePathsII ();
int [][] obstacleGrid = {
{ 0 , 0 , 0 },
{ 0 , 1 , 0 },
{ 0 , 0 , 0 }
};
System.out. println (solution. uniquePathsWithObstacles (obstacleGrid)); // Output: 2
}
}
Dp Solution
TC: O(m x n) — Each cell is computed once, making it much more efficient.
SC: O(m x n) for the dp array
public class UniquePathsIIDP {
public int uniquePathsWithObstacles ( int [][] obstacleGrid ) {
int m = obstacleGrid.length;
int n = obstacleGrid[ 0 ].length;
// If the starting or ending cell has an obstacle, return 0.
if (obstacleGrid[ 0 ][ 0 ] == 1 || obstacleGrid[m - 1 ][n - 1 ] == 1 ) {
return 0 ;
}
// DP array to store the number of ways to reach each cell.
int [][] dp = new int [m][n];
// Initialize the starting point.
dp[ 0 ][ 0 ] = 1 ;
// Fill the first column.
for ( int i = 1 ; i < m; i ++ ) {
dp[i][ 0 ] = (obstacleGrid[i][ 0 ] == 1 ) ? 0 : dp[i - 1 ][ 0 ];
}
// Fill the first row.
for ( int j = 1 ; j < n; j ++ ) {
dp[ 0 ][j] = (obstacleGrid[ 0 ][j] == 1 ) ? 0 : dp[ 0 ][j - 1 ];
}
// Fill the rest of the dp table.
for ( int i = 1 ; i < m; i ++ ) {
for ( int j = 1 ; j < n; j ++ ) {
if (obstacleGrid[i][j] == 1 ) {
dp[i][j] = 0 ; // If there's an obstacle, no paths to this cell.
} else {
dp[i][j] = dp[i - 1 ][j] + dp[i][j - 1 ]; // Sum of paths from top and left.
}
}
}
// The bottom-right corner will contain the number of unique paths.
return dp[m - 1 ][n - 1 ];
}
public static void main ( String [] args ) {
UniquePathsIIDP solution = new UniquePathsIIDP ();
int [][] obstacleGrid = {
{ 0 , 0 , 0 },
{ 0 , 1 , 0 },
{ 0 , 0 , 0 }
};
System.out. println (solution. uniquePathsWithObstacles (obstacleGrid)); // Output: 2
}
}
Space optimized
class Solution {
public int uniquePathsWithObstacles ( int [][] obstacleGrid ) {
int m = obstacleGrid.length;
int n = obstacleGrid[ 0 ].length;
if (obstacleGrid[ 0 ][ 0 ] == 1 ) {
return 0 ;
}
int [] prev = new int [n];
for ( int j = n - 1 ; j >= 0 ; j -- ) {
if (obstacleGrid[m - 1 ][j] == 1 ){
prev[j] = 0 ;
} else {
prev[j] = (j == n - 1 ) ? 1 : prev[j + 1 ];
}
}
// Fill the grid from bottom to top
for ( int i = m - 2 ; i >= 0 ; i -- ){
int [] curr = new int [n];
// Initialize the last column for the current row (only one way to reach the destination by moving down)
if (obstacleGrid[i][n - 1 ] != 1 ){
curr[n - 1 ] = prev[n - 1 ];
} else {
curr[n - 1 ] = 0 ;
}
// Update the current row based on the values from the previous row
for ( int j = n - 2 ; j >= 0 ; j -- ){
if (obstacleGrid[i][j] != 1 ){
curr[j] = curr[j + 1 ] + prev[j]; // Sum of ways from the cell to the right and the cell directly below
} else {
curr[j] = 0 ;
}
}
prev = curr;
}
return prev[ 0 ];
}
}