题目描述:
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.
题目分析:
本题和前一题基本一致,不过多加了一个障碍物。
首先,可以容易地想到,将有障碍物的地方路径数直接清零,就可以向前文中一样不断进行累加最后得到结果了。但注意到前文中循环是从1开始的,也就是说第一行和第一列都预先置为1了。这样,如果在第一行或第一列出现障碍物,直接使用前面的循环就会无法检出障碍物。
如果使用前文中第三种方法,也就是只使用一个数组的方法,我们就可以考虑将数组长度增加1,即使用一个n+1大小的数组。将数组首先置为1,0,0, … ,0,这时,如果执行一次循环count[j] = count[j - 1] + count[j]
,将会得到1,1,1, … ,1。
假设第一行网格的情况为g1: 0, 0, 1, 0, 0, 0。那对应的第一行的走法就是1, 1, 0, 0, 0, 0。我们只需要在执行循环的过程中遇到障碍物时将对应的位置count
设为0,就可以得到想要的效果了。
那如果第一列中出现了障碍物呢?如g2: 1, 0, 0, 0, 0, 0。如果这一行前面为g1,那对应的count数组应为:0, 1, 1, 1, 1, 1。我们不需对前面算法进行修改,就可以得到正确结果。
实现上述算法的代码如下所示,代码的时间复杂度为
O(mn)
,空间复杂度为
O(n)
。
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int m = obstacleGrid.size();
int n = m ? obstacleGrid[0].size() : 0;
vector<int> count(n, 0);
count[0] = 1;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(obstacleGrid[i][j])
count[j] = 0;
else if(j)
count[j] = count[j - 1] + count[j];
}
}
return count[n - 1];
}
};
其实一开始想直接修改使用count[i][j]
的算法,但是过程中觉得代码并没有想象中简介,遂放弃。在LeetCode的讨论区中有一个很简洁的实现,是增加了一行一列后的算法,空间复杂度为
O(mn)
,时间复杂度为
O(mn)
。在实际执行中,本算法会比前面算法略慢。现放在下面:
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int> > &obstacleGrid) {
int m = obstacleGrid.size() , n = obstacleGrid[0].size();
vector<vector<int>> dp(m+1,vector<int>(n+1,0));
dp[0][1] = 1;
for(int i = 1 ; i <= m ; ++i)
for(int j = 1 ; j <= n ; ++j)
if(!obstacleGrid[i-1][j-1])
dp[i][j] = dp[i-1][j]+dp[i][j-1];
return dp[m][n];
}
};
其实本题中比较巧妙的就是1,0,0, … , 0 数组的设置,这样可以很方便生成1, 1, 1, … , 1数组。