剑指leetcode—最小路径和

题目描述:给定一个包含非负整数的 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)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

方法二

二维数组动态规划

首先我们比较容易想得到的是从左上角开始推向右下角

  1. 定义状态dp[i][j]表示的是从起点出发到点[i,j]的最短路径的值
  2. 定义状态转移方程

dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j];

表示的是起点到grid【i】【j】的最短路径权值等于它所到达的前两个点的最短路径权值加grid【i】【j】本身的权值

  1. 定义初始值
    如果i=0,j=0,那么dp[i][j]=grid[i][j];

  2. 考虑优化,稍后会处理

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];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Devin Dever

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值