题目
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
解答1:递归
class Solution {
public static int xxx=0;
public int minPathSum(int[][] grid) {
int res=0;
for(int i=0;i<grid[0].length;i++){
res+=grid[0][i];
}
for(int i=1;i<grid.length;i++){
res+=grid[i][grid[0].length-1];
}
int allx=grid[0].length-1;
int ally=grid.length-1;
xxx=res;
digui(0,0,0,grid);
return xxx;
}
//sum当前和,x,y下一个要去的坐标
public void digui(int sum,int x,int y,int[][] grid){
if(sum>xxx){
return;
}
if(x>grid[0].length-1){
return ;
}
if(y>grid.length-1){
return ;
}
if(x==grid[0].length-1&&y==grid.length-1){
sum+=grid[y][x];
if(sum<xxx){
xxx=sum;
}
}else{
sum+=grid[y][x];
if(x+1>grid[0].length-1){
digui(sum,x,y+1,grid);
}else if(y+1>grid.length-1){
digui(sum,x+1,y,grid);
}else{
digui(sum,x,y+1,grid);
digui(sum,x+1,y,grid);
}
}
}
}
问题
超时
解答二:动态规划
class Solution {
public int minPathSum(int[][] grid) {
int[][] minpath=new int[grid.length][grid[0].length];
minpath[0][0]=grid[0][0];
for(int i=1;i<grid[0].length;i++){
minpath[0][i]=minpath[0][i-1]+grid[0][i];
}
for(int i=1;i<grid.length;i++){
minpath[i][0]=minpath[i-1][0]+grid[i][0];
}
for(int i=1;i<grid.length;i++){
for(int j=1;j<grid[0].length;j++){
minpath[i][j]=min(minpath[i-1][j],minpath[i][j-1])+grid[i][j];
}
}
return minpath[grid.length-1][grid[0].length-1];
}
public int min(int a,int b){
if(a>b){
return b;
}else{
return a;
}
}
}
思路
设起点到每个格子的最小路径和的二维数组为minpath[][],容易发现递推公式minpath[i][j]=min(minpath[i-1][j],minpath[i][j-1])+grid[i][j];按行、列顺序依次将minpath[][]填完。
总结
这是一种典型的动态规划方法。一般来说,只要问题可以划分成规模更小的子问题,并且原问题的最优解中包含了子问题的最优解,则可以考虑用动态规划解决。动态规划是一种将问题实例分解为更小的、相似的子问题,并存储子问题的解而避免计算重复的子问题,以解决最优化问题的算法策略。动态规划法优于递归方法的关键就在于,对于重复出现的子问题,只在第一次遇到时加以求解,并把答案保存起来,让以后再遇到时直接引用,不必重新求解。