Leetcode-63:Unique Paths II
Unique Paths
Description
You are given an m x n
integer array grid
. There is a robot initially located at the top-left corner (i.e., grid[0][0]
). The robot tries to move to the bottom-right corner (i.e., grid[m - 1][n - 1]
). The robot can only move either down or right at any point in time.
An obstacle and space are marked as 1
or 0
respectively in grid
. A path that the robot takes cannot include any square that is an obstacle.
Return the number of possible unique paths that the robot can take to reach the bottom-right corner.
The testcases are generated so that the answer will be less than or equal to 2 * 109
.
Example 1:
Input: obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
Output: 2
Explanation: There is one obstacle in the middle of the 3x3 grid above.
There are two ways to reach the bottom-right corner:
1. Right -> Right -> Down -> Down
2. Down -> Down -> Right -> Right
Example 2:
Input: obstacleGrid = [[0,1],[0,0]]
Output: 1
Constraints:
m == obstacleGrid.length
n == obstacleGrid[i].length
1 <= m, n <= 100
obstacleGrid[i][j]
is0
or1
.
Thinking
- If one stop is blocked, then itโs unreachable.
- How to calculate avaliable paths counts of reachable stops? Still use DP
Solution
DP
Basic idea follows same with ๐ Leetcode-62. Unique Paths, but need to do some actions for extreme situations(when facing blocked stop)
So the basic dp formula remains the same:
But notice that: F[i - 1][j]
is blocked, then the value itโs 0.(which means this stop is unreachable and canโt get the (i, j) of course)
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
if (obstacleGrid[0][0] == 1) {
return 0;
}
int[][] dp = new int[obstacleGrid.length][obstacleGrid[0].length];
dp[0][0] = 1;
for (int i = 0; i < dp.length; i++) {
for (int j = 0; j < dp[0].length; j++) {
if (i == 0 && j == 0 || obstacleGrid[i][j] == 1) {
continue;
}
dp[i][j] = getAvailablePathNum(obstacleGrid, dp, i - 1, j) + getAvailablePathNum(obstacleGrid, dp, i, j - 1);
}
}
return dp[dp.length - 1][dp[0].length - 1];
}
public int getAvailablePathNum(int[][] obstacleGrid, int[][] dp, int i, int j) {
// Error / Extreme Situation
if (i < 0 || j < 0 || obstacleGrid[i][j] == 1) {
return 0;
}
return dp[i][j];
}
}
Optimization
The getAvailablePathNum
is useless, so we wrap it in the main func.
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
if (obstacleGrid[0][0] == 1) {
return 0;
}
int[][] dp = new int[obstacleGrid.length][obstacleGrid[0].length];
dp[0][0] = 1;
for (int i = 0; i < dp.length; i++) {
for (int j = 0; j < dp[0].length; j++) {
if (i == 0 && j == 0 || obstacleGrid[i][j] == 1) {
continue;
}
int leftStop = i - 1 >=0 ? dp[i - 1][j] : 0;
int topStop = j - 1 >=0 ? dp[i][j - 1] : 0;
dp[i][j] = leftStop + topStop;
}
}
return dp[dp.length - 1][dp[0].length - 1];
}
}
Final Optimization
**Rolling Array**
When handling DP Problems, idea of Rolling Array will helps us optimize the performacne. Reduce space complexity effectively
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int n = obstacleGrid.length, m = obstacleGrid[0].length;
int[] f = new int[m];
f[0] = obstacleGrid[0][0] == 0 ? 1 : 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (obstacleGrid[i][j] == 1) {
f[j] = 0;
continue;
}
if (j - 1 >= 0 && obstacleGrid[i][j - 1] == 0) {
// That's where the thought works
// Only do the leftStop calculate, `case we've already done the topStop calculate through '+='
f[j] += f[j - 1];
}
}
}
return f[m - 1];
}
}
Reflection
- Remember the idea of Rolling Array when doing dp optimization.