当前位置: 首页 > web >正文

【LeetCode 热题 100】64. 最小路径和——(解法二)递推

Problem: 64. 最小路径和

文章目录

  • 整体思路
  • 完整代码
  • # 时空复杂度
    • 时间复杂度:O(m * n)
    • 空间复杂度:O(m * n)

整体思路

这段代码同样旨在解决 “最小路径和” 问题,但它采用的是一种 自底向上(Bottom-Up)的动态规划 方法,也称为 迭代法制表法 (Tabulation)。这种方法通过构建一个DP表(dp 二维数组),从起点开始,逐步计算出到达每个格子的最小路径和,最终得到终点的答案。

该实现通过巧妙地增加DP数组的维度并设置哨兵值,将边界条件的处理融入到统一的状态转移方程中,使得代码结构清晰。

  1. 状态定义与索引映射

    • 算法定义了一个二维DP数组 dp,大小为 (m+1) x (n+1)
    • dp[i][j] 的含义是:从起点 grid[0][0] 到达网格中的点 grid[i-1][j-1] 的最小路径和
    • 这是一个索引偏移的技巧。dp 数组的索引 (i, j) 对应了 m x n 网格中的索引 (i-1, j-1)
  2. 基础情况与边界处理 (Base Cases & Boundary Handling)

    • 设置“墙壁”:代码首先将 dp 数组的第0行和第0列(除了 dp[0][0]dp[1][0] 等)填充为 Integer.MAX_VALUE。这相当于在网格的上方和左方建立了一堵无限高的“墙”,确保路径只能从有效的格子内部过来,而不会从“网格外部”以一个较小的值(比如0)进入计算,从而干扰 Math.min 的结果。
    • 设置起点if (i == 0 && j == 0) 这个条件在循环内部处理了起点。dp[1][1] 被设置为 grid[0][0] 的值。这是整个DP计算的起点。
  3. 状态转移 (State Transition)

    • 算法使用两层嵌套循环来填充DP表。循环变量 ij 对应的是 m x n 网格的索引。
    • 在循环的每一步,计算 dp[i+1][j+1] 的值。
    • 状态转移方程是 dp[i + 1][j + 1] = Math.min(dp[i][j + 1], dp[i + 1][j]) + grid[i][j]
    • 我们来解析这个方程:
      • 要到达 grid[i][j](对应 dp[i+1][j+1]),只能从其上方的 grid[i-1][j](对应 dp[i][j+1])或左方的 grid[i][j-1](对应 dp[i+1][j])过来。
      • 因此,到达 grid[i][j] 的最小路径和,等于 grid[i][j] 的值加上“到达上方格子的最小路径和”与“到达左方格子的最小路径和”中的较小者。
      • 由于我们在第0行和第0列设置了极大值,当 i=0 时,dp[i][j+1] (即dp[0][j+1]) 是极大值,Math.min 会自动选择 dp[i+1][j],正确地处理了第一行的情况。对第一列同理。
  4. 返回结果

    • 当所有循环结束后,dp 数组已经完全填充。我们需要的最终答案,即到达终点 grid[m-1][n-1] 的最小路径和,就存储在 dp[m][n] 中。

完整代码

import java.util.Arrays;class Solution {/*** 计算从 m x n 网格左上角到右下角的最小路径和。* @param grid 包含非负整数的二维网格* @return 最小路径和*/public int minPathSum(int[][] grid) {int m = grid.length;int n = grid[0].length;// dp[i][j]: 表示从起点到网格 (i-1, j-1) 的最小路径和。// 使用 m+1, n+1 的大小是为了用第0行和第0列作为边界“墙”。int[][] dp = new int[m + 1][n + 1];// 初始化边界:将第0行设为极大值,作为上方的“墙”。Arrays.fill(dp[0], Integer.MAX_VALUE);// 遍历原始网格的行for (int i = 0; i < m; i++) {// 初始化边界:将每行的第0列设为极大值,作为左方的“墙”。dp[i + 1][0] = Integer.MAX_VALUE;// 遍历原始网格的列for (int j = 0; j < n; j++) {// 处理起点 (0,0) 的特殊情况if (i == 0 && j == 0) {// dp[1][1] 对应网格 (0,0),其最小路径和就是它自身的值。dp[1][1] = grid[i][j];} else {// 状态转移方程:// 到达网格 (i,j) 的最小路径和,等于// min(到达上方格子的最小和, 到达左方格子的最小和) + 当前格子的值。// dp[i][j+1] -> 上方格子// dp[i+1][j] -> 左方格子dp[i + 1][j + 1] = Math.min(dp[i][j + 1], dp[i + 1][j]) + grid[i][j];}}}// 最终答案是到达网格 (m-1, n-1) 的路径数,对应 dp[m][n]。return dp[m][n];}
}

# 时空复杂度

时间复杂度:O(m * n)

  1. 循环结构:算法使用了两层嵌套的 for 循环。
    • 外层循环从 i = 0 运行到 m-1,执行 m 次。
    • 内层循环从 j = 0 运行到 n-1,执行 n 次。
  2. 计算依据
    • 总的操作次数是内外层循环次数的乘积,即 m * n。初始化边界的操作复杂度是 O(m+n),被 m*n 主导。

综合分析
算法的时间复杂度为 O(m * n)

空间复杂度:O(m * n)

  1. 主要存储开销:算法创建了一个名为 dp 的二维整型数组来存储动态规划的所有中间状态。
  2. 空间大小:该数组的大小是 (m + 1) * (n + 1)

综合分析
算法所需的额外空间主要由 dp 数组决定,其空间复杂度为 O(m * n)

http://www.xdnf.cn/news/19506.html

相关文章:

  • DSPFilters实现低通滤波器(QT)
  • 【开题答辩全过程】以 留守儿童志愿者服务系统为例,包含答辩的问题和答案
  • Java全局异常处理器:优雅处理系统异常
  • 数学运算符号:跨越千年的智慧结晶与文明印记
  • strtok()字符串分隔函数
  • VideoPoet:Google发布的用于视频生成的大语言模型
  • 【C#】在一个任意旋转的矩形(由四个顶点定义)内绘制一个内切椭圆
  • SpringAI应用开发面试实录:核心技术、架构设计与业务场景全解析
  • 华为研发投资与管理实践(IPD)读书笔记
  • VSCode `tasks.json` 中 `tasks` 数组的详细解析
  • 语义分析:从读懂到理解的深度跨越
  • Photoshop - Ps 标尺
  • JVM参数配置调优指南
  • 在开发过程中经常遇到 OOM(内存溢出)问题,如何解决?
  • 解决IDEA 2025.2升级报错:Scannning Files to Index卡住问题分析与修复
  • 设计模式:外观模式(Facade Pattern)
  • 【Proteus仿真】开关控制系列仿真——开关控制LED/拨码开关二进制计数/开关和继电器控制灯灭
  • 第3章 乱码的前世今生-字符集和比较规则
  • 常见线程池的创建方式及应用场景
  • 将基于 Spring Boot 3.0.0 的 JavaWeb 应用部署到腾讯云并配置域名
  • Iterative loop of ML development|机器学习的迭代发展
  • C#基础(②音乐播发器MCI(Media Control Interface))
  • MySQL 常用语法
  • PortSwigger靶场之Stored XSS into HTML context with nothing encoded通关秘籍
  • Spring Boot 3.x 微服务架构实战指南
  • k8s中 discovery-token和token 的区别
  • Openstack Eproxy 2025.1 安装指南
  • 基于OpenCv做照片分析应用一(Java)
  • 学习记录(二十二)--Overleaf中生成的PDF左上角1.5em问题
  • 【AI编程工具】使用Cursor快速搭建一套小型项目管理系统