不同路径 | LeetCode-62 | 动态规划

动态规划练习题

LeetCode链接:62. 不同路径

题目1:62. 不同路径

1.题目描述

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

示例 1:

img

1
2
输入:m = 3, n = 7
输出:28

示例 2:

1
2
3
4
5
6
7
输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右
3. 向下 -> 向右 -> 向下

示例 3:

1
2
输入:m = 7, n = 3
输出:28

示例 4:

1
2
输入:m = 3, n = 3
输出:6

提示:

  • 1 <= m, n <= 100
  • 题目数据保证答案小于等于 $2 * 10^9$

2.题解

2.1 动态规划

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public int uniquePaths(int m, int n) {
// 创建一个大小为 m * n 的二维数组 dp,用于存储每个位置的路径数
int[][] dp = new int[m][n];

// 初始化第一行,机器人只能向右走,因此每个位置都有唯一一条路径
for(int i = 0; i < n; i++){
dp[0][i] = 1;
}

// 初始化第一列,机器人只能向下走,因此每个位置都有唯一一条路径
for(int i = 0; i < m; i++){
dp[i][0] = 1;
}

// 填充 dp 数组,其它位置的路径数为上方位置和左侧位置的路径数之和
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}

// 返回终点位置的路径数,即右下角的 dp[m-1][n-1]
return dp[m - 1][n - 1];
}
}

2.2 动态规划优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public int uniquePaths(int m, int n) {
// 创建一个长度为 n 的一维数组 dp,用于存储每列的路径数
// 初始时表示从起点 (0, 0) 到达每个列位置的路径数
int[] dp = new int[n];

// 初始化第一行,机器人只能向右走,因此第一行每个位置都有唯一一条路径
for(int i = 0; i < n; i++){
dp[i] = 1;
}

// 从第二行开始,逐行更新路径数
// 每一行的路径数可以通过当前列上方的路径数(dp[j])和左侧的路径数(dp[j - 1])累加得到
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
dp[j] = dp[j] + dp[j - 1]; // 上方的路径数 + 左侧的路径数
// dp[j] 代表上方的路径数
// dp[j - 1] 代表左侧的路径数
}
}

// 返回终点位置的路径数,即最后一列的 dp[n - 1]
return dp[n - 1];
}
}

2.3 组合数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public int uniquePaths(int m, int n) {
// 使用一个 long 类型的变量 result 来保存计算结果,避免中间计算过程中的整数溢出
long result = 1;

// 通过组合数学公式计算唯一路径数
// 循环的目的是计算公式 C(m+n-2, n-1) 或 C(m+n-2, m-1)
// 公式表示在 m-1 次向下移动和 n-1 次向右移动中选择 m-1 或 n-1 的组合数
// 即 C(m+n-2, n-1) = (n * (n+1) * ... * (m+n-2)) / ((m-1)!)
for(int x = n, y = 1; y < m; x++, y++){
result = result * x / y; // 每次计算当前组合的部分结果
}

// 返回最终结果,将 long 类型转换为 int 类型
return (int) result;
}
}

题目2:63. 不同路径 II

1.题目描述

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

网格中的障碍物和空位置分别用 10 来表示。

示例 1:

img

1
2
3
4
5
6
输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右

示例 2:

img

1
2
输入:obstacleGrid = [[0,1],[0,0]]
输出:1

提示:

  • m == obstacleGrid.length
  • n == obstacleGrid[i].length
  • 1 <= m, n <= 100
  • obstacleGrid[i][j]01

2.题解

2.1 动态规划

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] dp = new int[m][n];
for (int i = 0; i < n && obstacleGrid[0][i] == 0; i++)
dp[0][i] = 1;
for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++)
dp[i][0] = 1;

for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (obstacleGrid[i][j] == 1)
continue;
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
}
}
-------------本文结束感谢您的阅读-------------