力扣打卡:64. 最小路径和
解题思路
-
还是分析 暴力递归 的方法,然后再写出 自顶向下 的分析流程 -
分析 每个节点 要做的事情是什么,也就是分析出了 状态转移方程 -
状态转移方程 : 当前状态和子问题的结果有什么联系和关联 -
定义暴力递归的函数就认为这个函数可以得到需要的结果,对于子问题同样适合的需要的结果 -
只要将暴力递归写出来了,那么最后自顶向下的动态规划不就多了一个 检查 和 记录 的过程
最重要的流程还是当前的要做什么,和子问题的关联是什么,也就是状态转移的过程是什么
-
最终的 basecase 是什么,遇到了无解的子问题该怎么做 -
将暴力递归写出来了就可以了,重要的是分析状态转移方程 以及 定义暴力递归的函数时,就默认这个函数可以得到需要的结果 -
写暴力递归时,不要想着任何的优化,否则因为对动态规划的不熟悉,就会出现逻辑混乱的情况,也就是参数不知道怎么使用的情况
注意返回的值,索引越界的时候返回的是 Integer.MAX_VALUE
代码
class Solution {
public int minPathSum(int[][] grid) {
int[][] memo = new int[grid.length][grid[0].length];
for(int i=0; i<memo.length; i++) Arrays.fill(memo[i],-1);
return planB(memo, grid, 0, 0);
}
public int planA(int[][] grid, int m, int n){
if(m==grid.length || n==grid[0].length) return Integer.MAX_VALUE;
if(m==grid.length-1 && n==grid[0].length-1) return grid[m][n];
int bottom = planA(grid, m+1, n);
int right = planA(grid, m, n+1);
int val = Math.min(bottom, right) + grid[m][n];
return val;
}
public int planB(int[][] memo, int[][] grid, int m, int n){
if(m==grid.length || n==grid[0].length) return Integer.MAX_VALUE;
if(m==grid.length-1 && n==grid[0].length-1) return grid[m][n];
if(memo[m][n] != -1) return memo[m][n];
int bottom = planB(memo, grid, m+1, n);
int right = planB(memo, grid, m, n+1);
int val = Math.min(bottom, right) + grid[m][n];
memo[m][n] = val;
return memo[m][n];
}
}
|