先看一道题目
给定一个填充有非负数的m x n网格,找到一条从左上到右下的路径,该路径使沿其路径的所有数字之和最小。
注意:你只能在任何时间点向下或向右移动。
Input:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
Output: 7
思路就是1->3->1->1->1
关于这类型问题,比较好的做法就是使用动态规划,简单来说就是大事化小,小事化了。
把动态规划运用到这道题结题思路就是,分解、计算、合并。
先把数组设为a,横轴长度为n,竖为m
要求出a[0][0]到a[m - 1][n - 1]最短路径。根据分解思路。只要求出a[0][1]到a[m - 1][n - 1]的最短路径和a[1][0]到a[m - 1][n - 1]的最短路径,然后这两个路径比较即可得出最短的路径。
然后我们递归的去思考,要求出a[0][1]到a[m - 1][n - 1]最短路径,则只需要求出a[0][2]到a[m - 1][n - 1]的最短路径和a[1][1]到a[m - 1][n - 1]最短路径,两个路径相互比较取更短的即可。以此类推…
思路说完了,接下来我们看看代码
这里说下temp数组的作用,temp数组是用来保存已经求出的改点到a[m - 1][n - 1]的最短路径的值。
例如。要求出a[0][1]到a[m - 1][n - 1]最短路径,则需要求出a[1][1]到a[m - 1][n - 1]的最短路径。然后到了求a[1][0]到a[m - 1][n - 1]最短路径,则也需要求出a[1][1]到a[m - 1][n - 1]的最短路径,因为a[1][1]到a[m - 1][n - 1]的最短路径在之前已经求出,这个时候只需要从temp数组获取即可。不需要在额外递归计算了。即直接获取temp[1][1]即可
public class MinimumPathSum {
int[][] nums;
int[][] temp;
public int dp(int i, int j) {
// 判断该点到目标点的最短距离是否已经求出
if(temp[i][j] != 0) {
return temp[i][j];
}
// 如果到了目标点返回0,因为目标点到目标点距离为0
if(i == nums.length - 1 && j == nums[0].length - 1) {
return 0;
}
int x = Integer.MAX_VALUE;
int y = Integer.MAX_VALUE;
if(j < nums[0].length - 1) {
x = nums[i][j + 1] + dp(i, j + 1);
}
if(i < nums.length - 1) {
y = nums[i + 1][j] + dp(i + 1, j);
}
// 对比两个距离,取更小的值
temp[i][j] = x > y ? y : x;
return temp[i][j];
}
public int minPathSum(int[][] grid) {
nums = grid;
int m = grid.length;
int n = grid[0].length;
if(m == 1 && n == 1) {
return grid[0][0];
}
temp = new int[m][n];
return dp(0, 0) + nums[0][0];
}
public static void main(String[] args) {
MinimumPathSum minimumPathSum = new MinimumPathSum();
System.out.println(minimumPathSum.minPathSum(new int[][]{{3, 2, 3}, {4, 5, 6}}));
}
}