Unique Paths 系列
62. Unique Paths
介绍
A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).
How many possible unique paths are there?
解答
方法一
这道题目是很基本的动态规划题目。
大家应该很容易就能写出如下代码:
path[i][j]为位置(0,0)到位置(i,j)的路径数目。
位置(0,0)到位置(i,j-1)的路径是a,位置(0,0)到位置(i-1,j)的路径是b,那么位置(0,0)到位置(i-1,j)的路径就是a+b。
path[i][j] = path[i][j-1] + path[i-1][j]
class Solution {
public:
int uniquePaths(int m, int n) {
if(m > 0 && n > 0)
{
vector<vector<int>> path(m,vector<int>(n,1));
for(int i = 1; i < m; ++i)
{
for(int j = 1; j < n; ++j)
{
path[i][j] = path[i-1][j] + path[i][j-1];
}
}
return path[m-1][n-1];
}
return 0;
}
};
方法二
方法一使用了O(mn)的空间大小,但是实际上并不需要那么多。因为我们每次在使用的过程中实际上只需要本行中前一个元素的数据和本列中上一行的数据。
class Solution {
public:
int uniquePaths(int m,int n)
{
vector<int> cur(n,1);
vector<int> last(n,1);
for(int i = 1; i < m; i++)
{
for(int j = 1; j < n; ++j)
{
cur[j] = cur[j-1] + last[j];
}
last.swap(cur);
}
return last[n-1];
}
};
方法三:
好了,方法二中只需要两个vector就可以完成任务了。但是我们再观察一下,会发现对于关键语句
cur[j] = cur[j-1] + last[j];
即使我们只用一个cur 的数组也是能够完成任务的。为什么,因为cur[j]需要的是旧的cur[j]的值,在它使用的时候该值是没有被覆盖的。
所以最终的结果如下:
class Solution {
public:
int uniquePaths(int m,int n)
{
if(m < n) uniquePaths(n,m);
vector<int> cur(n,1);
for(int i = 1; i < m; ++i)
{
for(int j = 1; j < n; ++j)
{
cur[j] = cur[j] + cur[j-1];
}
}
return cur[n-1];
}
};
注意里面if(m < n) uniquePaths(n,m);
语句,可以让我们只需要让我们的空间复杂度下降到O(min(m,n))。
63. Unique Paths II
介绍
ollow 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.
题意:同样求从首元素到末尾元素的路径数目,但是如果数组中其值为1,意味着此元素是一个障碍,不可通过。输入参数一定合法。
解答
本题采用了动态规划的方法。
考虑一下:
1. 如果位置[i,j]上不是障碍物,如果我们已经知道位置(0,0)到位置(i,j-1)的路径是a,位置(0,0)到位置(i-1,j)的路径是b,那么位置(0,0)到位置(i-1,j)的路径就是a+b。
2. 如果考虑障碍物,只要位置[i,j]上是障碍物,位置(0,0)到位置(i,j)上的路径数目必然为0。
3. 如果位置(0,0)上不是障碍物,位置[0,0]到位置(0,0)上的路径数目应该为1。
考虑以上三点的关系,写出使用O(mn)空间大小的动态规划的代码并不困难。
但是我们这里提出了另外一种较省空间的动态规划代码。
数组help在遍历过程中记录着从二维数组的首元素到当前行,当前列元素的路径数目。
如初始时候数组help[0] = 1,代表位置[0,0]到位置(0,0)上的路径数目应该为1,其他下标上的值均为0。
然后在遍历过程中,help[j] = help[j-1] + help[j]。代表着位置(0,0)到位置(i,j)上的路径数目是位置(i,j-1)的路径(help[j-1]),和,位置(i-1,j)(这里是旧的help[j])的路径之和。
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int m = obstacleGrid.size(),n = obstacleGrid[0].size();
vector<int> help(n);
help[0] = 1;
for(int i = 0; i < m; ++i)
{
if(obstacleGrid[i][0]) help[0] = 0;
for(int j = 1; j < n; ++j)
{
if(obstacleGrid[i][j]) help[j] = 0;
else help[j] = help[j-1] + help[j];
}
}
return help[n-1];
}
};