今日任务:
资料来源:
题目
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
示例 1:
输入:m = 3, n = 7 输出:28
示例 2:
输入:m = 3, n = 2 输出:3 解释: 从左上角开始,总共有 3 条路径可以到达右下角。 1. 向右 -> 向下 -> 向下 2. 向下 -> 向下 -> 向右 3. 向下 -> 向右 -> 向下
示例 3:
输入:m = 7, n = 3 输出:28
示例 4:
输入:m = 3, n = 3 输出:6
提示:
很经典的两层数组的动态规划,还是按照动态规划五部曲走:
dp数组的含义和下标含义:从起点到达当前位置的可能的路径数量
确定递推公式:dp_array[i][j] = dp_array[i - 1][j] + dp_array[i][j - 1]
dp数组初始化:第一横行和第一竖行全部初始化为1,意味着从起点到达这些点的可能路径只有1条。由于n,m可能为1,所以dp_array[0][0]
也得初始化为1
确定遍历顺序:先行后列还是先列后行没有影响
举例推导:以用例1为例,它的dp数组应该是:
1 | 1 | 1 | 1 | 1 | 1 | 1 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
1 | 3 | 6 | 10 | 15 | 21 | 28 |
可见没有问题
提示
另外,这题还有一个数论的解法。首先,对于给定的m,n,从起点走到终点一定会走步,而且其中一定有步是向下走的,别管什么时候向下走。那也就是说,这题可以转化为一个数学问题:在个数中,挑出个数,可以有多少种挑法?结果就是。
pythonclass Solution:
def uniquePaths(self, m: int, n: int) -> int:
# 初始化
dp_array = [[0] * n] * m
for i in range(n):
dp_array[0][i] = 1
for i in range(m):
dp_array[i][0] = 1
# 开始dp
for i in range(1, m):
for j in range(1, n):
dp_array[i][j] = dp_array[i - 1][j] + dp_array[i][j - 1]
return dp_array[-1][-1]
javaclass Solution {
public int uniquePaths(int m, int n) {
int[][] dp_array = new int[m][n];
for (int i = 0; i < m; i++) {
dp_array[i][0] = 1;
}
for (int i = 0; i < n; i++) {
dp_array[0][i] = 1;
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp_array[i][j] = dp_array[i - 1][j] + dp_array[i][j - 1];
}
}
return dp_array[m - 1][n - 1];
}
}
gofunc uniquePaths(m int, n int) int {
dpArray := make([][]int, m)
for i := range dpArray {
dpArray[i] = make([]int, n)
dpArray[i][0] = 1
}
for i := range dpArray[0] {
dpArray[0][i] = 1
}
for i := 1; i < m; i++ {
for j := 1; j < n; j++ {
dpArray[i][j] = dpArray[i - 1][j] + dpArray[i][j - 1]
}
}
return dpArray[m - 1][n - 1]
}
题目
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
示例 1:
输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]] 输出:2 解释:3x3 网格的正中间有一个障碍物。 从左上角到右下角一共有 2 条不同的路径: 1. 向右 -> 向右 -> 向下 -> 向下 2. 向下 -> 向下 -> 向右 -> 向右
示例 2:
输入:obstacleGrid = [[0,1],[0,0]] 输出:1
提示:
不是,这题给的用例也太坑,完全看不出来这二维数组是按行存的还是按列存的气死个人。
这题的思路和上面的62是完全一致的,但是有的地方不一样。一方面是遍历dp数组的过程中,如果遇到障碍,说明这块是永远不可抵达的,所以要将其置为0;另一方面是初始化dp数组的过程中,如果遇到障碍,那么从这个障碍之后的所有位置都要置0,因为初始化的那一行/列本来就只有一条路,有个障碍在那里直接就把这一条路堵死了。
pythonfrom typing import List
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
if obstacleGrid[0][0] == 1:
return 0
# 这题的obstacleGrid是按列存的 obstacleGrid[i]代表的是一列的数据 注意
# 初始化
for i in range(1, len(obstacleGrid)): # 因为是一旦遇到障碍 后面赋值为0 所以不能从头开始循环 否则下一个初始化会有问题
if obstacleGrid[i][0] == 0:
obstacleGrid[i][0] = 1
else:
# 一旦遇到障碍 后面全部赋值为0
obstacleGrid[i][0] = 0
if i < len(obstacleGrid) - 1:
obstacleGrid[i + 1][0] = 1
for i in range(len(obstacleGrid[0])):
if obstacleGrid[0][i] == 0:
obstacleGrid[0][i] = 1
else:
obstacleGrid[0][i] = 0
if i < len(obstacleGrid[0]) - 1:
obstacleGrid[0][i + 1] = 1
for i in range(1, len(obstacleGrid)):
for j in range(1, len(obstacleGrid[0])):
if obstacleGrid[i][j] == 1:
obstacleGrid[i][j] = 0
else:
obstacleGrid[i][j] = obstacleGrid[i - 1][j] + obstacleGrid[i][j - 1]
return obstacleGrid[-1][-1]
javaclass Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
if (obstacleGrid[0][0] == 1) return 0;
for (int i = 1; i < obstacleGrid.length; i++) {
if (obstacleGrid[i][0] == 0) {
obstacleGrid[i][0] = 1;
} else {
obstacleGrid[i][0] = 0;
if (i < obstacleGrid.length - 1) {
obstacleGrid[i + 1][0] = 1;
}
}
}
for (int i = 0; i < obstacleGrid[0].length; i++) {
if (obstacleGrid[0][i] == 0) {
obstacleGrid[0][i] = 1;
} else {
obstacleGrid[0][i] = 0;
if (i < obstacleGrid[0].length - 1) {
obstacleGrid[0][i + 1] = 1;
}
}
}
for (int i = 1; i < obstacleGrid.length; i++) {
for (int j = 1; j < obstacleGrid[0].length; j++) {
if (obstacleGrid[i][j] == 0) {
obstacleGrid[i][j] = obstacleGrid[i - 1][j] + obstacleGrid[i][j - 1];
} else {
obstacleGrid[i][j] = 0;
}
}
}
return obstacleGrid[obstacleGrid.length - 1][obstacleGrid[0].length - 1];
}
}
gofunc uniquePathsWithObstacles(obstacleGrid [][]int) int {
if obstacleGrid[0][0] == 1 {
return 0
}
for i := 1; i < len(obstacleGrid); i++ {
if obstacleGrid[i][0] == 1 {
obstacleGrid[i][0] = 0
if i < len(obstacleGrid) - 1 {
obstacleGrid[i+1][0] = 1
}
} else {
obstacleGrid[i][0] = 1
}
}
for i := 0; i < len(obstacleGrid[0]); i++ {
if obstacleGrid[0][i] == 1 {
obstacleGrid[0][i] = 0
if i < len(obstacleGrid[0]) - 1 {
obstacleGrid[0][i + 1] = 1
}
} else {
obstacleGrid[0][i] = 1
}
}
for i := 1; i < len(obstacleGrid); i++ {
for j := 1; j < len(obstacleGrid[0]); j++ {
if obstacleGrid[i][j] == 1 {
obstacleGrid[i][j] = 0
} else {
obstacleGrid[i][j] = obstacleGrid[i - 1][j] + obstacleGrid[i][j - 1]
}
}
}
return obstacleGrid[len(obstacleGrid) - 1][len(obstacleGrid[0]) - 1]
}
本文作者:御坂19327号
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!