LeeCode64,最小路径和
难度:中等
目录
作者思路
小老鼠走迷宫算法
class Solution {
public int length = Integer.MAX_VALUE;
public int minPathSum(int[][] grid) {
search(grid,0,0,grid.length-1,grid[0].length-1,grid[0][0]);
return length;
}
public void search (int[][] grid,int beginRow,int beginCol,int desRow,int desCol,int len) {
if (beginRow == desRow && beginCol == desCol) {
length = Math.min(len,length);
}
if (len > length) {
return;
}
if (beginCol + 1 < grid[0].length) {
search(grid,beginRow,beginCol+1,desRow,desCol,len + grid[beginRow][beginCol+1]);
}
if (beginRow + 1 < grid.length) {
search(grid,beginRow+1,beginCol,desRow,desCol,len + grid[beginRow+1][beginCol]);
}
}
}
思想和代码简述
- 该算法是通过递归的方式,将里面所有的路径都走一遍,当走到终点的时候就把其路径和记录下来,直到最后选出一个最小的值返回
- 1.形参分别是起点对应的行和列,终点对应的行和列,还有到达某一个点时的路径总和
- 2.如果发现起点等于终点,说明,走完了,到达了终点,此刻记录一下总路程
- 3.否则,判断一下递归过程中是否len大于之前记录下来的length,如果大于,说明这个路径到达终点的路程一定比原来的大,所以,没必要继续下去,直接结束即可
- 4.否则,继续递归前进(详细请转到迷宫回溯问题!)
问题
反省
- 又是这些极端案例,不过没办法,还是得从极端案例里面直到自己的不足,所以,通过学习我总结了最小路径问题的相关算法,即,当最小路径问题的规模比较小时,我们可以通过搜索算法(即小老鼠走迷宫)去求解类似的问题,当问题规模比较大时,我们可以通过动态规划算法去解决
- 通过此次案例,我们不仅知道了动态规划算法可以用于回文串问题,还可以用于最小路径问题,有效的收获
官方解法-动态规划算法
思路分析
- 由动态规划算法,我们直接知道了最重要的步骤就是填表了,所以,我们要怎么样去填表呢?即怎么样构造一个dp数组呢?
- 1.根据动态规划的思想,下一个结果必须和上一个结果有关系,所以,我们不妨设所有的点都是局部目的地,这样,就可以体现局部目的地到最终目的地的关联思想
- 2.去到某个目的地只有两种走法,从上往下或从左往右,我们从里面选一个最优的路径,充当该目的地的结果
- 3.通过以上操作,我们就可以得出最终的结果
- 4,该方法的动态规划还是比较难阐述的,所以,请看案例分析
案例分析
- 第一个是原数组,第二个是dp数组
- 推演过程
- grid[0][0]为终点,只能直接跳进去,说dp[0][0] = 1
- grid[0][1]为终点,只能从左边走进去,所以dp[0][1] = 1 + 3 = 4
- grid[0][2]为终点,同理只能从左边走过去,所以dp[0][2] = 4 + 1 = 5
- 注意:之前的dp[0][1]代表从(0,0)走到(0,1),走到(0,2)需要前面的两步,所以是+4
- grid[1][0]为终点,只能从上面走下去,所以dp[1][0] = 1 + 1 = 2
- 同理...
- grid[1][1]为终点,可以从上面和左面走下去,我们发现从左边走的话路程比较小,所以dp[1][1] = 2 +5 = 7 如果上面走的话就是9了
- 同理...得出最终的dp表
- 我们可以发现,每一次走的都是最好的,而且下一次最好的是建立在上一次最好的基础上的,所以,当我们走到终点的时候他就是最好的,就是我们想要的答案,这就是动态规划
代码实现
class Solution {
public int minPathSum(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0].length == 0) {
return 0;
}
var dp = new int[grid.length][grid[0].length];
dp[0][0] = grid[0][0];
for (int i = 1; i < grid.length; i++) {
dp[i][0] = dp[i-1][0] + grid[i][0];
}
for (int j = 1; j < grid[0].length; j++) {
dp[0][j] = dp[0][j-1] + grid[0][j];
}
for (int i = 1; i < grid.length; i++) {
for (int j = 1; j < grid[0].length; j++) {
dp[i][j] = Math.min(dp[i-1][j] + grid[i][j],dp[i][j-1]+grid[i][j]);
}
}
return dp[grid.length-1][grid[0].length-1];
}
}
代码分析
- 1.首先,我们先校验数组是否为特殊情况(数组不存在,行或列为0),如果是,直接返回0
- 2.创建对应的dp数组,并将dp[0][0]按照案例步骤初始化
- 3.分别先初始化第一列,第一行
- 因为只有一种走法
- 4.初始化其他位置,并选择最优的位置
- 注意:这里是dp[?][?] + grip[?][?],这才能体现累加并且前后联系的思想
结论
算法都是抽象的,不好讲,更需要大家的心领神会,如果大家有什么不懂的地方可以找我,我写这个博客的时候也挺烧脑的,不知道怎么描述,最后,我来总结以下几点
1.动态规划适用场景
2.算法思想
3.案例分析即代码实现