题目描述:给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-path-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
方法一
暴力法
暴力法参考leetcode官方题解
利用递归,对于每个元素我们考虑两条路径,向右走和向下走,在这两条路径中挑选路径权值和较小的一个。
cost(i,j)=grid[i][j]+min(cost(i+1,j),cost(i,j+1)),
public class Solution {
public int calculate(int[][] grid, int i, int j) {
if (i == grid.length || j == grid[0].length) return Integer.MAX_VALUE;
if (i == grid.length - 1 && j == grid[0].length - 1) return grid[i][j];
return grid[i][j] + Math.min(calculate(grid, i + 1, j), calculate(grid, i, j + 1));
}
public int minPathSum(int[][] grid) {
return calculate(grid, 0, 0);
}
}
作者:LeetCode
链接:https://leetcode-cn.com/problems/minimum-path-sum/solution/zui-xiao-lu-jing-he-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
方法二
二维数组动态规划
首先我们比较容易想得到的是从左上角开始推向右下角
- 定义状态dp[i][j]表示的是从起点出发到点[i,j]的最短路径的值
- 定义状态转移方程
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j];
表示的是起点到grid【i】【j】的最短路径权值等于它所到达的前两个点的最短路径权值加grid【i】【j】本身的权值
-
定义初始值
如果i=0,j=0,那么dp[i][j]=grid[i][j]; -
考虑优化,稍后会处理
java实现
class Solution {
public int minPathSum(int[][] grid) {
int m=grid.length;
int n=grid[0].length;
int[][] dp = new int[m][n];
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
{
if(i==0&&j==0)
dp[i][j]=grid[i][j];
else if(i==0&&j<n)
dp[i][j]=grid[i][j]+dp[i][j-1];
else if(j==0&&i<m)
dp[i][j]=grid[i][j]+dp[i-1][j];
else
dp[i][j]=Math.min(dp[i-1][j],dp[i][j-1])+grid[i][j];
}
return dp[m-1][n-1];
}
}
方法三
二维动态规划
(不需要额外的存储空间,可以在grid数组上进行修改)
java实现
class Solution {
public int minPathSum(int[][] grid) {
int m=grid.length;
int n=grid[0].length;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
{
if(i==0&&j==0)
grid[i][j]=grid[i][j];
else if(i==0&&j<n)
grid[i][j]=grid[i][j]+grid[i][j-1];
else if(j==0&&i<m)
grid[i][j]=grid[i][j]+grid[i-1][j];
else
grid[i][j]=Math.min(grid[i-1][j],grid[i][j-1])+grid[i][j];
}
return grid[m-1][n-1];
}
}
leetcode官方题解中是采用从右下角推向左上角的策略进行规划的,可以自行去学习
方法四:
一维数组动态规划
这一个解法中我们可以使用一个一维数组来代替二维数组,dp数组的大小和行的大小n相同,对于每一个状态,只需要考虑左方和上方的数组节点,初始化dp数组的第一个元素为左上角的元素,然后向右移动更新每个dp【j】值
dp【j】=grid(i,j)+min(dp(j),dp(j-1))
对每一行重复这个过程,然后向下行移动,最后返回结果dp【n-1】
class Solution {
public int minPathSum(int[][] grid) {
int m=grid.length;
int n=grid[0].length;
int[] dp = new int[n];
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
{
if(i==0&&j==0)
dp[j]=grid[i][j];
else if(i==0&&j<n)
dp[j]=grid[i][j]+dp[j-1];
else if(j==0&&i<m)
dp[j]=grid[i][j]+dp[j];
else
dp[j]=Math.min(dp[j],dp[j-1])+grid[i][j];
}
//注意这里不是dp【m-1】.
return dp[n-1];
}
}