最小路径和(给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。)

博客给出一个包含非负整数的 m x n 网格,要求找出从左上角到右下角路径上数字总和最小的路径,且每次只能向下或向右移动一步。还给出示例及输出结果,并阐述解题思路,使用动态规划计算从(0,0)走到(i,j)的最小路径和。

给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

示例:

输入:
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。

解题思路:dp[i][j]代表从(0,0)走到(i,j)的最小路径和则

dp[0][i]来自第一行的累加

dp[i][0]来自第一列的累加

dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1]) + grip[i][j](来自当前位置的走法无非向下或向右,选两者中代价最小的)

 

public class Test0519 {
    public static void main(String[] args) {
        Solution s =new Solution();
        int[][] grid = {{1,3,1},{1,5,1},{4,2,1}};
        System.out.println(s.minPathSum(grid));
    }
}

class Solution {
    public int minPathSum(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] dp = new int[m][n];
        dp[0][0] = grid[0][0];
        for(int i = 0;i<m;i++){
            for(int j = 0;j<n;j++){
                if(i == 0 || j==0){
                    if(i==0 && j !=0){
                        dp[i][j] = dp[i][j-1] + grid[i][j];
                    }else if(i != 0 && j == 0){
                        dp[i][j] = dp[i-1][j] + grid[i][j];
                    }
                }else{
                    dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1]) + grid[i][j];
                }
            }
        }
        return dp[m-1][n-1];
    }
}

 

<think>首先,用户的问题是关于在二维网格中找到从左上角右下角最小路径每次只能向右或向下移动。这是一个经典的动态规划问题。 我需要参考用户提供的引用内容。引用[1]描述了问题,引用[2]、[3]、[4]、[5]提供了动态规划的解决方案。这些引用包括JavaC++的代码实现,以及一些解释。 关键点: - 网格大小是mn。 - 每个单元格包含非负整数。 - 只能向右或向下移动。 - 目标是找到从(0,0)(m-1,n-1)路径,其路径最小。 动态规划思路: 1. 创建一个dp数组,大小与网格相同,dp[i][j]表示从(0,0)(i,j)最小路径。 2. 初始化: - dp[0][0] = grid[0][0],因为起点就是它本身。 - 对于第一(i=0),只能向右走,所以dp[0][j] = dp[0][j-1] + grid[0][j]。 - 对于第一(j=0),只能向下走,所以dp[i][0] = dp[i-1][0] + grid[i][0]。 3. 对于其他单元格(i>0且j>0),dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j],因为可以从上方或左方移动过来。 4. 最终结果在dp[m-1][n-1]。 引用[4]提到空间复杂度可以优化到O(n),通过只存储一或一的值。 我的回答需要: - 使用中文。 - 结构清晰,逐步解释。 - 包含LaTeX公式:内用$...$,独立公式用$$...$$。 - 在回答末尾生成相关问题。 - 自然地添加引用标识。 回答结构: 1. **问题描述**:简要重述问题。 2. **动态规划思路**:解释算法步骤。 3. **状态转移方程**:用LaTeX写公式。 4. **代码实现**:提供Python代码,因为用户示例中有Python代码。 5. **复杂度分析**:时间空间复杂度。 6. **空间优化**:简要提到优化方法。 7. **生成相关问题**:在最后添加相关问题。 生成相关问题: 基于用户的问题,相关问题可以是: 1. 如何优化空间复杂度? 2. 如果网格中有负数怎么办? 3. 如何扩展到允许对角线移动? 4. 实际应用场景是什么? 引用标识:在相关地方添加,如[^1]、[^2]等。 现在,构建回答: - 问题描述:用户已给出,我简要重述。 - 动态规划思路:逐步解释。 - 状态转移方程: - 初始:$dp[0][0] = grid[0][0]$ - 第一:$dp[0][j] = dp[0][j-1] + grid[0][j]$ - 第一:$dp[i][0] = dp[i-1][0] + grid[i][0]$ - 其他:$dp[i][j] = \min(dp[i-1][j], dp[i][j-1]) + grid[i][j]$ - 代码:用Python实现,因为用户示例是Python。 - 复杂度:时间O(mn),空间O(mn)(可优化到O(n))。 - 优化:提到滚动数组优化。 - 相关问题:出3-4个。 确保LaTeX正确: - 内:$dp[i][j]$ - 独立:$$ dp[i][j] = \min(dp[i-1][j], dp[i][j-1]) + grid[i][j] $$ 引用: - 引用[1]描述问题,[^1] - 引用[2]、[3]、[5]有代码解释,[^2]、[^3]、[^5] - 引用[4]有空间优化,[^4] 在回答中自然地添加引用,如“根据动态规划方法[^2],我们可以...”</think>### 最小路径问题 您的问题是在一个 $m \times n$ 的二维网格中,从左上角 $(0,0)$ 出发,每次只能向右或向下移动,最终到达右下角 $(m-1,n-1)$,目标是找到所有可能路径路径最小的值。路径定义为路径上所有网格数字总和。这是一个经典的动态规划问题,下面我将逐步解释解决方案。 #### 1. **动态规划思路** 动态规划的核心是构建一个状态数组 $dp$,其中 $dp[i][j]$ 表示从起点 $(0,0)$ 到达网格位置 $(i,j)$ 的最小路径。状态转移基于移动限制(只能向右或向下): - **起点**:$dp[0][0]$ 就是网格起点值。 - **边界处理**: - **第一($i=0$)**:只能向右移动,因此 $dp[0][j] = dp[0][j-1] + grid[0][j]$。 - **第一($j=0$)**:只能向下移动,因此 $dp[i][0] = dp[i-1][0] + grid[i][0]$。 - **一般位置($i>0$ 且 $j>0$)**:可以从上方 $(i-1,j)$ 或左方 $(i,j-1)$ 移动过来,选择路径更小的方向: $$ dp[i][j] = \min(dp[i-1][j], dp[i][j-1]) + grid[i][j] $$ 最终,$dp[m-1][n-1]$ 即为所求的最小路径[^2][^3][^5]。 #### 2. **算法步骤** 1. **初始化**: - 若网格为空,返回 0。 - 创建 $dp$ 数组,大小与网格相同。 - $dp[0][0] = grid[0][0]$。 2. **填充边界**: - 遍历第一:$dp[0][j] = dp[0][j-1] + grid[0][j]$($j$ 从 1 到 $n-1$)。 - 遍历第一:$dp[i][0] = dp[i-1][0] + grid[i][0]$($i$ 从 1 到 $m-1$)。 3. **填充内部**: - 双重循环遍历 $i$ 从 1 到 $m-1$,$j$ 从 1 到 $n-1$: $$ dp[i][j] = \min(dp[i-1][j], dp[i][j-1]) + grid[i][j] $$ 4. **返回结果**:$dp[m-1][n-1]$。 #### 3. **代码实现(Python)** 以下是完整的 Python 实现,代码注释详细解释了每一步: ```python def minPathSum(grid): if not grid or not grid[0]: return 0 m, n = len(grid), len(grid[0]) # 初始化 dp 数组 dp = [[0] * n for _ in range(m)] dp[0][0] = grid[0][0] # 起点 # 填充第一 for j in range(1, n): dp[0][j] = dp[0][j-1] + grid[0][j] # 填充第一 for i in range(1, m): dp[i][0] = dp[i-1][0] + grid[i][0] # 填充其他位置 for i in range(1, m): for j in range(1, n): dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] return dp[m-1][n-1] # 示例网格 grid = [ [1, 3, 1], [1, 5, 1], [4, 2, 1] ] print(minPathSum(grid)) # 输出: 7 (路径 1→1→4→2→1 或 1→1→2→1→1) ``` #### 4. **复杂度分析** - **时间复杂度**:$O(m \times n)$,因为需要遍历整个网格一次。 - **空间复杂度**:$O(m \times n)$,用于存储 $dp$ 数组。但可以优化到 $O(n)$(或 $O(m)$),通过只存储一或一的值(滚动数组优化)[^4]。 #### 5. **空间优化方法** 通过滚动数组优化空间: - 使用一维数组 $dp$ 代替二维数组。 - 更新规则: - 初始化 $dp[0] = grid[0][0]$。 - 第一:$dp[j] = dp[j-1] + grid[0][j]$。 - 后续:$dp[0]$ 更新为 $dp[0] + grid[i][0]$(第一),然后 $dp[j] = \min(dp[j], dp[j-1]) + grid[i][j]$(其他)。 - 优化后空间复杂度为 $O(n)$[^4]。 ### 相关问题 基于最小路径问题,以下是几个延伸问题: 1. **如何优化最小路径算法的空间复杂度?**(例如,使用滚动数组将空间复杂度从 $O(mn)$ 降到 $O(n)$) 2. **如果网格中存在负数,动态规划方法是否仍然有效?需要如何调整?** 3. **最小路径问题在实际应用中有哪些场景?**(例如,机器人导航、资源优化等) 4. **如何扩展问题以允许对角线移动?动态规划状态转移方程会如何变化?** [^1]: [分支限界]给定一个矩阵m*n,从左上角开始每次只能向右或者向下走,最后到右下角的位置共有多少种路径给定一个mn的矩阵,从左上角开始每次只能向右或向下移动,最后到达右下角的位置,路径上的所有数字累加起来作为这条路径路径。编写程序求所有路径中的最小路径。 [^2]: 64. 最小路径给定一个包含非负整数的 m x n 网格 grid ,找出一条左上角右下角路径,使得路径...。使用动态规划的方法解决。 [^3]: 64. 最小路径 给定一个包含非负整数的 m x n 网格 grid ,找出一条左上角右下角路径,使得路径上...。说明:每次只能向下或者向右移动一步。 [^4]: 给定一个包含非负整数的 m x n 网格找出一条左上角右下角路径,使得路径上的数字总和最小...。空间复杂度可以优化,例如每次只存储上一的 dp 值,则可以将空间复杂度优化到 O(n)。 [^5]: m x n 网格找出一条左上角右下角路径,使得路径上的数字总和最小。说明:每次只能向下或者向右移动一步。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值