Tuesday, September 16, 2014

Leetcode: Unique Paths II

Follow up for "Unique Paths":
Now consider if some obstacles are added to the grids. How many unique paths would there be?
An obstacle and empty space is marked as 1 and 0 respectively in the grid.
For example,
There is one obstacle in the middle of a 3x3 grid as illustrated below.
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
The total number of unique paths is 2.
Note: m and n will be at most 100.
Understand the problem:
The problem is similar to the Unique Path I, whereas the obstacles existed in the grid. So for each point, we check if it is an obstacle. If yes, we return 0, means all paths are unable to cross this point. 

A Recursive DP Solution:
public class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        if (obstacleGrid == null || obstacleGrid.length == 0) {
            return 0;
        }
        
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        
        if (obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1) {
            return 0;
        }
        
        int[][] dp = new int[m][n];
        
        return uniquePathsHelper(0, 0, m, n, obstacleGrid, dp);
    }
    
    private int uniquePathsHelper(int m, int n, int rows, int cols, int[][] obstacleGrid, int[][] dp) {
        if (m > rows - 1 || n > cols- 1) {
            return 0;
        }
        
        if (obstacleGrid[m][n] == 1) {
            return 0;
        }
        
        if (m == rows - 1 && n == cols - 1) {
            return 1;
        }
        
        
        if (dp[m][n] != 0) {
            return dp[m][n];
        }
        
        dp[m][n] = uniquePathsHelper(m + 1, n, rows, cols, obstacleGrid, dp) + uniquePathsHelper(m, n + 1, rows, cols, obstacleGrid, dp);
        return dp[m][n];
    }
}

Discussion:
Note the difference between this solution with the Unique Path I, where as we start from (m, n) and ended with (m == 1 || n == 1). Why the previous method does not work here? That is because (m == 1 || n == 1) we cannot simply return 1 because there could be an obstacle in the last row or column. So we have to check until we reach the bottom-right point. 

However, this solution will cause TLE error at OJ. So we must find out another way.

Iterative DP Solution:
Similar to the iterative DP solution in Unique Path I, we use dp[i][j] to store the number of unique paths from (0,0). Be careful for the first row or column, if there is an obstacle, we set the elements after it as zero. 

Code (Java):
public class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        if (obstacleGrid == null || obstacleGrid.length == 0) {
            return 0;
        }
        
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        
        if (obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1) {
            return 0;
        }
        
        int[][] dp = new int[m][n];
        
        // check the first row
        for (int i = 0; i < n; i++) {
            if (obstacleGrid[0][i] == 0) {
                dp[0][i] = 1;
            } else {
                dp[0][i] = 0;
                break;
            }
        }
        
        // check the first column
        for (int i = 0; i < m; i++) {
            if (obstacleGrid[i][0] == 0) {
                dp[i][0] = 1;
            } else {
                dp[i][0] = 0;
                break;
            }
        }
        
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                if (obstacleGrid[i][j] == 0) {
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
                }
            }
        }
        
        return dp[m - 1][n - 1]; 
    }
}

A one-dimensional DP solution:
public class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        if (obstacleGrid == null || obstacleGrid.length == 0) {
            return 0;
        }
        
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        
        if (obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1) {
            return 0;
        }
        
        int[] dp = new int[n];
        dp[0] = 1;
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (obstacleGrid[i][j] == 1) {
                    dp[j] = 0;
                } else if (j > 0) {
                    dp[j] = dp[j] + dp[j - 1];
                }
            }
        }
        return dp[n - 1];
    }
}





No comments:

Post a Comment