目录
这是动态规划的题目,我是采用递归来做的,当然非递归也阔以。
题目:
题解思路:
既然是递归实现的动态规划,就想,如果我们想得到这个点的最小路径和,那么这个值应该等于该点(m,n)方格内填着的数字 + 上一个点的最小路径和。而“上一个点”我们应该选最小路径和值最小的那个才能保证值的最小。
我们需要有退出递归的条件,一个是数组越界的时候,我们返回0。第二个就是,当递归到第一行或第一列的时候,由于我们之前说“上一个点”是选取最小路径和最小的那个,而位于第一行或第一列的时候执行
Math.min(grid[m-1][n-1] + dfs(m-1,n,grid),grid[m-1][n-1]+dfs(m,n-1,grid));
语句的时候,肯定有一个dfs返回值为0,取最小的时候就一定会取到0,这会导致结果错误。
所以,我们应该把这种情况也当作退出条件。即 当位于第一行的某个点时,最短路径和 = 该点的值 + 左边一个点的最短路径和 。当位于第一列的某个点时, 最短路径和 = 该点的值 + 上面一个点的最短路径和。
为了防止递归导致过多的重复计算,使用数组来存储每个点的最小路径和,这样,当准备重复递归计算这个点的最小路径和时,就直接把值返回而不进行递归计算。
题解代码:
/**
* 最小方格路径和
* */
public class Problem64 {
public static int min = 0;
//我用f数组来保存每一个点的最小路径和的值
public static int[][] f = null;
public static int minPathSum(int[][] grid) {
f = new int[201][201];
int m = grid.length;
int n = grid[0].length;
for(int i=0;i<m;i++){
Arrays.fill(f[i],-1);
}
min = dfs(m,n,grid);
return min;
}
//递归边赋值边求最小路径和
public static int dfs(int m,int n,int[][] grid){
//防止递归时导致数组下标越界
if(m<1||n<1){
return 0;
}
//这里是对特殊行和列的赋值
if(m==1){
f[m-1][n-1] = grid[m-1][n-1] + dfs(m,n-1,grid);
return f[m-1][n-1];
}else if(n==1){
f[m-1][n-1] = grid[m-1][n-1] + dfs(m-1,n,grid);
return f[m-1][n-1];
}
if(f[m-1][n-1]!=-1){
return f[m-1][n-1];
}
f[m-1][n-1]=Math.min(grid[m-1][n-1] + dfs(m-1,n,grid),grid[m-1][n-1]+dfs(m,n-1,grid));
return f[m-1][n-1];
}
public static void main(String[] args){
System.out.println(minPathSum(new int[][]{{1,3,1},{1,5,1},{4,2,1}}));
}
}