Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.
Example 1:
[[1,3,1],
[1,5,1],
[4,2,1]]
Given the above grid map, return 7. Because the path 1→3→1→1→1 minimizes the sum.
一眼看出这是一个用递归能解决的题,只要遍历一次所有的路径,找到路径的最小值便可。而题目规定只能往下或者往右,终结条件也给出了是右下角的那个数字,当前的解依赖于下一个元素(或右,或下)的最优解,只需要把子问题层层递推下去便可。子问题便是下一个元素为起点的所有路径中最短的那条。将每个元素为起点的当前最优路径看成一个状态,那么状态转移方程式建立如下:
从当前元素开始最短路径=当前元素值+从左边元素开始的最短路径与从下边开始元素最短路径之间最短的。
未优化代码:
class Solution {
public static int minPathSum(int[][] grid) {
/*
* 遍历所有路线,记录最短的
* 规则只能向右或者向下移动,所以需要判断碰到右边界或者上边界的情况
* 如果遇到右边界只能往下,如果遇到下边界只能往右走,直到遇到右边界下边界的地方,即右下角终结点
*/
return minSum(grid,0,0);
}
public static int minSum(int[][] grid,int down,int right) {
int m=grid.length-1;//行数
int n=grid[0].length-1;//列数
if(down==m&&right<n)//下边界
return grid[down][right]+minSum(grid,down,right+1);
if(down<m&&right==n)
return grid[down][right]+minSum(grid,down+1,right);
if(down==m&&right==n)
return grid[m][n];
int sum1=grid[down][right]+minSum(grid,down+1,right);
int sum2=grid[down][right]+minSum(grid,down,right+1);
if(sum1>sum2)
return sum2;
else
return sum1;
}
}
这个代码在LeetCode上是过不了的,耗时太长
下面进行下优化,这个问题中很明显的一点就是对重复子问题求解了很多次,所以耗时是指数级的,如何重叠子问题的?那便是使用备忘录方法,利用空间换取时间效率,我们开辟一个数组,将已经计算过的子问题,存储下来,下次遇到直接用就行了。
public static int minPathSum(int[][] grid) {
/*
* 遍历所有路线,记录最短的 规则只能向右或者向下移动,所以需要判断碰到右边界或者上边界的情况
* 如果遇到右边界只能往下,如果遇到下边界只能往右走,直到遇到右边界下边界的地方,即右下角终结点
*/
int flag[][] = new int[300][300]; // 开辟数组记录已计算值,300足以应付此题数据。
return minSum(grid, 0, 0, flag);
}
public static int minSum(int[][] grid, int down, int right, int[][] flag) {
int m = grid.length - 1;// 行数
int n = grid[0].length - 1;// 列数
if (flag[down][right] == 0) { // 如果记录数组中没有值。执行计算。如果有值直接拿出来
if (down == m && right < n)// 下边界
{
flag[down][right] = grid[down][right] + minSum(grid, down, right + 1, flag); // 往右
return flag[down][right];
}
if (down < m && right == n) // 右边界
{
flag[down][right] = grid[down][right] + minSum(grid, down + 1, right, flag);// 往左
return flag[down][right];
}
if (down == m && right == n)// 终点
return grid[m][n];
int sum1 = grid[down][right] + minSum(grid, down + 1, right, flag);
int sum2 = grid[down][right] + minSum(grid, down, right + 1, flag);
if (sum1 > sum2) {
flag[down][right] = sum2;
return sum2;
} else {
flag[down][right] = sum1;
return sum1;
}
} else {
return flag[down][right];
}
}
这个代码是可以顺利通过的,时间效率高。