动态规划入门必刷:不同路径 & 最小路径和 详解

目录

一、不同路径(中等难度)

题目描述

核心思路分析

代码实现(Java)

复杂度分析

二、最小路径和(中等难度)

题目描述

核心思路分析

代码实现(Java)

复杂度分析

三、两道题的对比与总结

四、写在最后


今天我们来啃两道经典的动态规划入门题 ------不同路径最小路径和。它们都是网格 DP 的代表,难度中等,思路一脉相承,非常适合用来理解 "如何用动态规划解决路径问题"。下面我会用通俗的语言讲清思路、给出代码,并做优化分析,直接可以当博客发布。


一、不同路径(中等难度)

题目描述

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 "Start" )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 "Finish" )。问总共有多少条不同的路径?

核心思路分析

这道题是典型的网格路径计数 DP 问题,核心是找到递推关系:

  1. 状态定义dp[i][j] 表示从起点 (0,0) 走到 (i,j) 的不同路径数。
  2. 递推公式 :因为只能从上方 (i-1,j) 或左方 (i,j-1) 走到 (i,j),所以:dp[i][j] = dp[i-1][j] + dp[i][j-1]
  3. 边界条件
    • 第一行的所有点:只能从左边走过来,所以 dp[0][j] = 1
    • 第一列的所有点:只能从上方走过来,所以 dp[i][0] = 1
  4. 优化空间:因为每一行的状态只依赖上一行和当前行左边的值,我们可以用一维数组来优化空间复杂度。

代码实现(Java)

java

运行

复制代码
// 二维数组版(直观易懂)
public int uniquePaths(int m, int n) {
    int[][] dp = new int[m][n];
    // 初始化第一行
    for (int j = 0; j < n; j++) {
        dp[0][j] = 1;
    }
    // 初始化第一列
    for (int i = 0; i < m; i++) {
        dp[i][0] = 1;
    }
    // 递推计算
    for (int i = 1; i < m; i++) {
        for (int j = 1; j < n; j++) {
            dp[i][j] = dp[i-1][j] + dp[i][j-1];
        }
    }
    return dp[m-1][n-1];
}

// 一维数组优化版(空间复杂度O(n))
public int uniquePathsOptimized(int m, int n) {
    int[] dp = new int[n];
    // 初始化第一行
    for (int j = 0; j < n; j++) {
        dp[j] = 1;
    }
    // 逐行递推
    for (int i = 1; i < m; i++) {
        for (int j = 1; j < n; j++) {
            dp[j] = dp[j] + dp[j-1];
        }
    }
    return dp[n-1];
}

复杂度分析

  • 时间复杂度:O(m * n),遍历整个网格一次。
  • 空间复杂度:
    • 二维版:O(m * n)
    • 一维优化版:O(n)(n 为列数)

二、最小路径和(中等难度)

题目描述

给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。说明:每次只能向下或者向右移动一步。

核心思路分析

这道题是上一题的 "升级版",从计数路径数 变成了求路径和的最小值,核心 DP 思想是相通的:

  1. 状态定义dp[i][j] 表示从起点 (0,0) 走到 (i,j) 的最小路径和。
  2. 递推公式 :因为只能从上方或左方过来,所以取两者的最小值加上当前格子的值:dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
  3. 边界条件
    • 第一行:只能从左边来,所以 dp[0][j] = dp[0][j-1] + grid[0][j]
    • 第一列:只能从上方来,所以 dp[i][0] = dp[i-1][0] + grid[i][0]
  4. 优化空间 :同样可以用一维数组优化,甚至直接在原 grid 上修改,做到空间复杂度 O(1)

代码实现(Java)

java

运行

复制代码
// 二维数组版(直观易懂)
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 j = 1; j < n; j++) {
        dp[0][j] = dp[0][j-1] + grid[0][j];
    }
    // 初始化第一列
    for (int i = 1; i < m; i++) {
        dp[i][0] = dp[i-1][0] + grid[i][0];
    }
    // 递推计算
    for (int i = 1; i < m; i++) {
        for (int j = 1; j < n; j++) {
            dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1]) + grid[i][j];
        }
    }
    return dp[m-1][n-1];
}

// 原地修改版(空间复杂度O(1))
public int minPathSumInPlace(int[][] grid) {
    int m = grid.length;
    int n = grid[0].length;
    // 初始化第一行
    for (int j = 1; j < n; j++) {
        grid[0][j] += grid[0][j-1];
    }
    // 初始化第一列
    for (int i = 1; i < m; i++) {
        grid[i][0] += grid[i-1][0];
    }
    // 递推计算
    for (int i = 1; i < m; i++) {
        for (int j = 1; j < n; j++) {
            grid[i][j] += Math.min(grid[i-1][j], grid[i][j-1]);
        }
    }
    return grid[m-1][n-1];
}

复杂度分析

  • 时间复杂度:O(m * n),遍历整个网格一次。
  • 空间复杂度:
    • 二维版:O(m * n)
    • 原地修改版:O(1)(直接在原数组上操作)

三、两道题的对比与总结

表格

题目 核心问题 递推公式 优化方向
不同路径 路径计数 dp[i][j] = dp[i-1][j] + dp[i][j-1] 一维数组优化空间
最小路径和 路径和求最小值 dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] 原地修改数组

这两道题是网格动态规划的入门模板,它们的解题套路完全可以迁移到其他类似题目中:

  1. 状态定义 :通常定义 dp[i][j] 为到达 (i,j) 时的目标值(路径数、路径和、最大值等)。
  2. 递推关系:根据题目允许的移动方向(只能右 / 下),找到当前状态与上一状态的关系。
  3. 边界初始化:处理第一行和第一列,因为它们只能从一个方向过来。
  4. 空间优化:利用滚动数组或原地修改,将空间复杂度从二维降到一维甚至常数级。

四、写在最后

刷完这两道题,你会发现动态规划的核心就是 **"大事化小,小事化了"**:把大问题拆解成一个个小的子问题,找到它们之间的递推关系,然后用空间换时间,一步步算出最终结果。

相关推荐
wabs6661 小时前
关于图论【卡码网117.软件构建的思考】
数据结构·算法·软件构建·图论·卡码网
mifengxing2 小时前
LeetCode 41.缺失的第一个正数|Hard题O(n)+O(1)最优解法深度解析
java·算法·leetcode·排序算法
Tongzhi20262 小时前
从部署到运维:通芝科技无感考勤一体机的全流程效率解析
运维·数据结构·科技·算法·贪心算法
Wang's Blog3 小时前
AI Agent白手起家30: 动态示例选择器之根据长度选择 Few Shot 示例
算法
oyguyteggytrrwwwrt4 小时前
自制交叉线路识别算法
算法
手写码匠4 小时前
华为云Flexus+DeepSeek征文|Dify 多智能体协同编排实战:R1 规划 + V3 执行,构建企业 Agent 团队
人工智能·深度学习·算法·aigc
晓天衡宇•评测社区5 小时前
FSR-Bench 前沿科学推理榜单发布:GPT-5.5 居首,“会推理”未必“能答对”
算法
程序喵大人6 小时前
【C++进阶】STL算法与函数对象 - 02 sort为什么需要随机访问迭代器
开发语言·c++·算法
hanlin037 小时前
动态规划专练:力扣第121、122题
笔记·算法·leetcode
To_OC7 小时前
LC 74 搜索二维矩阵:换皮的二分查找,我居然一开始没看出来
javascript·算法·leetcode