【网格 dp】B000_LC_最小路径和(记忆化搜索 / bfs / dp)

本文深入探讨了寻找二维网格中从左上角到右下角的最小路径和问题,通过四种方法:递归、记忆化搜索、bfs和动态规划进行求解,最终详细解析了动态规划的实现过程及其时间与空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、题目描述

Given a m x n grid filled with non-negative numbers,
find a path from top left to bottom right which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.

Input:
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
Output: 7
Explanation: Because the path 1→3→1→1→1 minimizes the sum.

二、题解

方法一:递归(超时)

递归三部曲:

  • 结束条件:遇到网格最后一格。
  • 本层递归的责任
    • 边界区域:只能往下面或者右边走。
    • 非边界区域:有两种选择,取二者的最小权值。
  • 返回值:当前位置权值 + 下一步的权值。

代码已删…

方法二:记忆化搜索

定义 memo 数组把一些重复计算的结果记忆下来,留给后面的的递归使用。

private int search(int[][] grid, int r, int c) {
  if (memo[r][c] != 0)
    return memo[r][c];
  if (r == m - 1 && c == n - 1) {
    memo[r][c] = grid[r][c];
    return grid[r][c];
  }
  if (r == m - 1) {	//到达最右一列,只能向下走
    memo[r][c] = grid[r][c] + search(grid, r, c + 1);
    return memo[r][c];
  }
  if (c == n - 1) { //到达最后一行,只能向右走
    memo[r][c] = grid[r][c] + search(grid, r - 1, c);
    return memo[r][c];
  }					//非边界区域
  memo[r][c] = grid[r][c] + Math.min(search(grid, r, c + 1), search(grid, r + 1, c));
  return memo[r][c];
}

复杂度分析

  • 时间复杂度:O(m∗n)O(m * n)O(mn)
  • 空间复杂度:O(m∗n)O(m * n)O(mn)

方法三:bfs(超时)

  • 定义内部类 Pos,存储网格每个点的坐标以 (x, y) 及当前所走过的路径的权值总和 sum。
  • bfs 从结点 (0, 0) 开始,每次添加两个方向的结点,直到网格的终点。
  • 到达终点 (m−1,n−1)(m-1, n-1)(m1,n1) 后,如果路径权值总和比 minSum 小,那么更新 minSum 为当前权值。

方法四:dp

基于方法二,我们可以把程序从递归改为迭代,原理都一样。

动态规划三部曲:

  • 状态定义:dp[i][j] 的值代表直到走到 (i,j) 的最小路径和。

  • 转移方程

    • 起点 dp[i][j] = grid[i][j]
    • 非矩阵边界: dp[i][j] = grid[i][j] + min(dp[i - 1][j], dp[i][j - 1])
    • 左边是矩阵边界即 i = 0,j != 0 时,dp[i][j] = dp[i][j−1] + grid[i][j]
    • 上边是矩阵边界 即 i != 0,j == 0 时,dp[i][j] = dp[i - 1][j] + grid[i][j]
  • 初始状态 dp[0][0] = grid[0][0]

class Solution {
public:
    int minPathSum(vector<vector<int>>& g) {
        int n = g.size(), m = g[0].size(), f[n+1][m+1];
        memset(f, 0, sizeof f);

        for (int i = 0; i < n; i++)
    	for (int j = 0; j < m; j++) {
            if (i == 0 && j == 0)f[i][j] = g[i][j];
    	    else if (j == 0)     f[i][j] = f[i-1][j] + g[i][j]; //从左边来
    		else if (i == 0)     f[i][j] = f[i][j-1] + g[i][j];//从上面来
    		else                 f[i][j] = min(f[i-1][j], f[i][j-1]) + g[i][j];
    	}
    	return f[n-1][m-1];
    }
};

复杂度分析

  • 时间复杂度:O(m×n)O(m × n)O(m×n)
  • 空间复杂度:O(m×n)O(m × n)O(m×n)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值