动态规划相关题目都可以参考以下五个步骤进行解答:
状态表⽰
状态转移⽅程
初始化
填表顺序
返回值
后面题的解答思路也将按照这五个步骤进行讲解。
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
示例 2:
输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1.向右 -> 向下 -> 向下
2.向下 -> 向下 -> 向右
3.向下 -> 向右 -> 向下
示例 3:
输入:m = 7, n = 3
输出:28
示例 4:
输入:m = 3, n = 3
输出:6
class Solution {
public int uniquePaths(int m, int n) {
}
}
这⾥选择第⼆种定义状态表⽰的⽅式:
初始化:
可以在最前⾯加上⼀个「辅助结点」,帮助我们初始化。使⽤这种技巧要注意两个点:
填表顺序:
根据「状态转移⽅程」的推导来看,填表的顺序就是「从上往下」填每⼀⾏,在填写每⼀⾏的时候「从左往右」。
返回值:
根据「状态表⽰」,我们要返回 dp[m][n] 的值
class Solution {
public int uniquePaths(int m, int n) {
// 1. 创建 dp 表
// 2. 初始化
// 3. 填表
// 4. 返回值
int[][] dp = new int[m + 1][n + 1];
dp[0][1] = 1;
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];
return dp[m][n];
}
}
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
示例 1:
输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1.向右 -> 向右 -> 向下 -> 向下
2.向下 -> 向下 -> 向右 -> 向右
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
}
}
本题为不同路径的变型,只不过有些地⽅有「障碍物」,只要在「状态转移」上稍加修改就可解决。
这⾥选择第⼆种定义状态表⽰的⽅式:dp[i][j] 表⽰:⾛到 [i, j] 位置处,⼀共有多少种⽅式。
但是, [i - 1, j] 与 [i, j - 1] 位置都是可能有障碍的,此时从上⾯或者左边是不可能到达 [i, j] 位置的,也就是说,此时的⽅法数应该是0。
由此我们可以得出⼀个结论,只要这个位置上「有障碍物」,那么我们就不需要计算这个位置上的值,直接让它等于 0 即可。
在本题中,添加⼀⾏,并且添加⼀列后,只需将 dp[1][0] 的位置初始化为 1 即可。
填表顺序:
根据「状态转移」的推导,填表的顺序就是「从上往下」填每⼀⾏,每⼀⾏「从左往右」。
返回值:
根据「状态表⽰」,我们要返回的结果是 dp[m][n]
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] dp = new int[m + 1][n + 1];
dp[0][] = 1;
for(int i = 1; i <= m ; i++) {
for(int j = 1; j <= n; j++) {
if(obstacleGrid[i - 1][j - 1] == 0) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
}
return dp[m][n];
}
}
现有一个记作二维矩阵 frame 的珠宝架,其中 frame[i][j] 为该位置珠宝的价值。拿取珠宝的规则为:
只能从架子的左上角开始拿珠宝
每次可以移动到右侧或下侧的相邻位置
到达珠宝架子的右下角时,停止拿取
注意:珠宝的价值都是大于 0 的。除非这个架子上没有任何珠宝,比如 frame = [[0]]。
class Solution {
public int jewelleryValue(int[][] frame) {
}
}
这⾥选择第⼆种定义状态表⽰的⽅式:
dp[i][j] 表⽰:⾛到 [i, j] 位置处,此时的最⼤价值。
我们要的是最⼤值,因此状态转移⽅程为:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + grid[i][j] 。
在本题中,「添加⼀⾏」,并且「添加⼀列」后,所有的值都为 0 即可。
填表顺序:
根据「状态转移⽅程」,填表的顺序是「从上往下填写每⼀⾏」,「每⼀⾏从左往右」。
返回值:
根据「状态表⽰」,我们应该返回 dp[m][n] 的值。
class Solution {
public int jewelleryValue(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int[][] dp = new int[m + 1][n + 1];
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]) + grid[i - 1][j-1];
return dp[m][n];
}
}
关于《【算法优选】 动态规划之路径问题——壹》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!