64 最小路径和(递归、动态规划)

1. 问题描述:

给定一个包含非负整数的 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

2. 思路分析:

① 首先对于关于尝试路径的问题,我们都可以使用递归来求解,可以分为向下走与向右走两个平行状态,在一开始需要传入起点表示当前的位置,使用if判断来决定是否向右走或者是向下走,加入可以的话那么递归下去,在递归的方法中传入一个变量k,用来记录到达当前位置的路径和是多少,能够往下走那么就将下一个点的值加入到路径和中,表示能够到达下一个路径的和是多少,但是递归的话耗时比较大,对于数据量大的通不过,只能够通过25个测试用例

在官方提供的递归代码中也是值得学习的,它是具有返回值的递归,递归的时候是将当前位置的值加上向下递归与向左递归的最小值即可,思路值得我们学习

② 由于递归超时了,还是想其他的办法解决,其实这道题目还是比较简单理解的,我们很容易发现在最短路径和形成的过程中到达当前路径中的当前位置的最小值是由左边元素与上边元素的最小值加上当前位置的值形成的,结合矩阵是很容易理解的,我们只要在循环中一直这样做就可以得到当前位置的最小值,那么最终到达右下角的肯定也是最小值

③ 在领扣的题解中还可以使用一维数组来解决,但是的话比较难理解,使用二维数组的话在理解上难度会小一点

3. 代码如下:

我自己写的递归代码:

import java.util.Scanner;
public class Solution {
    /*使用一个全局变量来记录最小值*/
    int min = Integer.MAX_VALUE;
    public int minPathSum(int[][] grid) {
        dfs(grid, grid[0][0], grid.length, grid[0].length, 0, 0);
        return min;
    }

    public void dfs(int[][] grid, int k, int row, int col, int r, int c) {
        if (r == row - 1 && c == col - 1){
            min = Math.min(min, k);
            return;
        }
        /*提前剪枝: 两个平行状态*/
        /*向右走*/
        if (c + 1 < col){
            dfs(grid, k + grid[r][c + 1], row, col, r, c + 1);
        }
        if (r + 1 < row){
            dfs(grid, k + grid[r + 1][c], row, col, r + 1, c);
        }
    }
}

官方有返回值的递归:

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);
    }
}

我自己写的动态规划代码:

import java.util.Scanner;
public class Solution {
    public int minPathSum(int[][] grid) {
        int r = grid.length, c = grid[0].length;
        int dp[][] = new int[r][c];
        dp[0][0] = grid[0][0];
        /*初始化第一行*/
        for (int i = 1; i < c; ++i){
            dp[0][i] = dp[0][i - 1] + grid[0][i];
        }
        /*初始化第一列*/
        for (int i = 1; i < r; ++i){
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        }
        for (int i = 1; i < r; ++i){
            for (int j = 1; j < c; ++j){
                /*逻辑其实很好理解到达当前最短的路径和: 左边元素与上边元素的最小值*/
                dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }
        return dp[r - 1][c - 1];
    }
}
发布了569 篇原创文章 · 获赞 153 · 访问量 59万+

猜你喜欢

转载自blog.csdn.net/qq_39445165/article/details/105235312