64.给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例 1
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。
- 我的原始人解法:与求不同路径数一样,假设 f(i,j) 为到达左边 (i,j) 的最小总和,只需得到 f(m-1,n-1) 即可,如果贴着墙了,还是一样,比如贴着上墙壁的 (0,1) 此时到达 (0,1) 只可能是从 (0,0) 也就是他的左边过来的, 贴着左墙壁同理,否则就可能为从左或上过来的,根据题目要求,我们取最小值即可
-
public int minPathSum(int[][] grid) { int m = grid.length; int n = grid[0].length; int[][] ans = new int[m][n]; ans[0][0] = grid[0][0]; for(int i=0;i<m;i++){ for(int j=0;j<n;j++){ int temp = grid[i][j]; if(i>0 && j>0){ ans[i][j] = Math.min(ans[i-1][j],ans[i][j-1])+temp; }else if(i>0){ ans[i][j] = ans[i-1][j] + temp; }else if(j>0){ ans[i][j] = ans[i][j-1] + temp; } } } return ans[m-1][n-1]; }
- 题号:64
- 作者解法:思路一致,但代码更简洁
-
public int minPathSum(int[][] grid) { int m = grid.length, n = grid[0].length; int[][] f = new int[m][n]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (i == 0 && j == 0) { f[i][j] = grid[i][j]; } else { // 贴着上墙则取 int 最大值,这样就一定会被 Math.min 淘汰, // 等于排除了从上墙壁里面钻出来的可能 int top = i - 1 >= 0 ? f[i - 1][j] + grid[i][j] : Integer.MAX_VALUE; // 同理 int left = j - 1 >= 0 ? f[i][j - 1] + grid[i][j] : Integer.MAX_VALUE; f[i][j] = Math.min(top, left); } } } return f[m - 1][n - 1]; }
- 关于使用一维数组来存储二维数组的信息。先说一下二维数组的坐标转成一维数组的下标。说一下我个人的理解,一个 ,m x n 的网格,以 2 x 3 的网格为例,坐标为 (0,0) 的是第 1 个方块,对应到一维数组的下标也就是 0,同理得到 (0,1) => 1, (0,2) => 2,当坐标为 (1,0),由于它上面还有 1 行,而一行有 n 个,也就是 3 个,所以他就是第 1+3 也就是第 4 个方块,对应一维数组下标为 3。此时可以看出二维坐标转一位数组下标就是 i*n + j,因为遍历的 j 一定小于 n (不然数组下标越界了), 所以同理一维数组下标转成二维数组坐标就是 (index/n, index%n)。但是这时怎么用这个一维数组还是个问题,我们尝试用数组来记录这条路径。比如 2 x 2 的网格,最小总和路径为 (0,0) -> (0,1) -> (1,1),按照第几个方块来看其实就是 1->2->4,对应数组下标也就是 0 -> 1 -> 3,那么比如数组 g,
g[3(第 4 个方块)] = 1(到达第 4 个方块的前一个方块为第 2 个方块)
,g[1(第 2 个方块)] = 0(到达第 2 个方块的前一个方块为第 1 个方块)
,这样就等于存储了坐标移动的路径。