一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?
例如,上图是一个7 x 3 的网格。有多少可能的路径?

示例 1:
输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右
示例 2:
输入: m = 7, n = 3
输出: 28
升级版
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
说明:m 和 n 的值均不超过 100。
示例 1:
输入:
[
[0,0,0],
[0,1,0],
[0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-paths
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
先看第一题,开始想过使用回溯剪枝的方法进行深度优先搜索。但是当数据跑到23x12就超时了,因为一层一层地迭代下去进行回溯操作是很耗费时间地。使用二维数组标记当前节点是否访问过,然后迭代。代码如下:
class Solution {
public int sum = 0;
public int[] x = {1,0};
public int[] y = {0,1};
public int uniquePaths(int m, int n) {
int[][] map = new int[n][m];
for(int i=0; i<n; ++i){
for(int j=0; j<m; j++){
map[i][j] = 0;
}
}
dfs(0,0,m,n,map);
return sum;
}
public void dfs(int dx,int dy,int m,int n,int[][] map){
if(dx==m-1 && dy==n-1) {
sum++;
return ;
}
for(int i=0; i<2; ++i) {
int t = dx + x[i];
int u = dy + y[i];
if(t>=0 && t<m && u>=0 && u<n && map[u][t]==0) {
map[u][t] = 1;
dfs(t,u,m,n,map);
map[u][t] = 0;
}
}
return ;
}
}
虽然范围是[1,100],最大也就是循环10000次。所以引入记忆化搜索的方法解决该问题。
考虑到当机器人沿着上边界或者沿着左边界走时(只能右移和下移),所以在二重循环里面判断如果是边界点,就直接令dp数组为1,表示只有一条路径到达当前节点,continue跳到下一次循环。如果是内部节点,来到该节点只能通过上面和左边的节点,所以dp[i][j] = dp[i-1][j] + dp[i][j-1];表示当前节点的路径数为上面节点和左面节点的总和。之后直接返回dp[m-1][n-1]即为结果。代码如下:
class Solution {
public int sum = 0;
public int uniquePaths(int m, int n) {
int[][] dp = new int[n][m];
for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
if(i==0 || j==0) {
dp[i][j] = 1;
continue;
}
dp[i][j] = dp[i-1][j] + dp[i][j-1] ;
}
}
return dp[n-1][m-1];
}
}
最后看第二道题中,相对于第一题而言,引入了一个障碍物的概念。我们这样考虑,在第一题的动态规划的基础上,假设这个障碍物如果是在上边界或者左边界,那么边界上面障碍物之后的所有得节点都是无法到达的,所以当不能完全按照第一题的解法。这时我们判断给我们的矩阵序列的节点是否为1,如果为1,直接让当前dp[i][j] = 0,表示当前节点是无法到达的,以便于被它所影响到的节点的迭代。
之后判断为0节点的位置,如果在边界,那么只加上左边或上边节点的路径数量,如果是内部节点,那么策略不变,加来自两个方向的路径数量。最后返回的是想要到达节点的dp[i][j]所代表的值。代码如下:
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] dp = new int[m][n];
dp[0][0] = 1;
for(int x=0; x<m; x++){
for(int y=0; y<n; y++){
if(obstacleGrid[x][y] == 1){
dp[x][y] = 0;
continue;
}
if(x>0 && y>0){
dp[x][y] = dp[x-1][y] + dp[x][y-1] ;
} else if(x>0 && y==0) {
dp[x][y] = dp[x-1][y];
} else if(y>0 && x==0) {
dp[x][y] = dp[x][y-1] ;
}
}
}
return dp[m-1][n-1] ;
}
}
对于

这篇博客讨论了如何使用动态规划解决LeetCode中的不同路径问题,包括没有障碍物的标准问题和有障碍物的升级版问题。通过二维数组实现记忆化搜索,博主解释了如何计算机器人在网格中从左上角到右下角的不同路径数量,并给出了详细的代码实现。
363

被折叠的 条评论
为什么被折叠?



