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

【多维动态规划】64. 最小路径和(面试真题+面试官调整后的题目)

64. 最小路径和

难度:中等
力扣地址:https://leetcode.cn/problems/minimum-path-sum/description/

在这里插入图片描述

1. 原题以及解法

1.1 题目

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

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

示例 1:

在这里插入图片描述

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

示例 2:

输入:grid = [[1,2,3],[4,5,6]]
输出:12

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 200
  • 0 <= grid[i][j] <= 200

1.2 分析过程

首先应当分析简单的情况:如下图所示,长度为 2 x 2 时的最小路径和过程

在这里插入图片描述
接着我们需要计算尺寸更大情况的最小路径。
在这里插入图片描述 在这里插入图片描述
分析结论

  • 上图已经提到转移方程,即 dp[i][k] = min(dp[i-1][k], dp[i][k-1]) + grid[i][k] 。但是需要注意这个公式的适用场景:i >= 1, k >= 1
  • 对于 i == 0 以及 k == 0 的情况(第一行与第一列),通过累加的方式即可更新dp值。

1.3 解题代码

class Solution {
public:int minPathSum(vector<vector<int>>& grid) {int row = grid.size();int column = grid[0].size();vector<vector<int>> dp(row, vector<int>(column));dp[0][0] = grid[0][0];// 第一行每个点的最小路径for (int i = 1; i < column; i++) {dp[0][i] = grid[0][i] + dp[0][i - 1];}// 第一列每个点的最小路径for (int i = 1; i < row; i++) {dp[i][0] = grid[i][0] + dp[i - 1][0];}/** 对于 dp[i][k] 的计算规则为* dp[i][k] = min(dp[i - 1][k], dp[i][k - 1]) + grid[i][k]*/for (int i = 1; i < row; i++) {for (int k = 1; k < column; k++) {dp[i][k] = min(dp[i - 1][k], dp[i][k - 1]) + grid[i][k];}}return dp[row - 1][column - 1];}
};

2. 拓展(带条件的多维动态规划)

注:据可靠保熟消息,本题是一道面试题,面试官首先考察了与力扣第64题相同的,然后在这个基础上添加了这个条件,希望参与者手撕代码。

在这个题的基础上添加限制条件:存在一个或多个障碍物堵塞路径,如果题目中无路径则返回 -1

如下是一个基于力扣第64题调整后的新题目:

2.1 拓展题

问题描述

给定一个 m x n 的网格,其中每个单元格包含一个非负整数,表示到达该单元格的费用。同时,网格中可能存在若干不可通行的障碍物,障碍物用 -1 表示。你的任务是找到从左上角 (0, 0) 到右下角 (m-1, n-1) 的路径,使得路径上的数字总和最小。如果不存在路径,请返回 -1

输入

  • 一个二维数组 gridgrid[i][j] 为网格中的数值,其中 grid[i][j] >= 0 表示可通行,grid[i][j] == -1 表示不可通行的障碍物。

输出

  • 返回从左上角到右下角的路径上的数字总和的最小值。如果不存在这样的路径,返回 -1

示例 1

输入
grid = [[1, 3, 1],[1, -1, 1],[4, 2, 1]
]
输出
7
解释

最优路径为 (0,0) -> (1,0) -> (2,0) -> (2,1) -> (2,2),路径费用为 1 + 1 + 4 + 1 + 1 = 7

当然可以,这里是一个包含不可通行案例的示例:


示例 2

输入
grid = [[1, 3, -1],[2, -1, 3],[-1, 2, 1]
]
输出
-1
解释

在这个网格中,位置 (2, 0), (1, 1), (0,2) 是一个障碍物,导致从左上角 (0, 0) 到右下角 (2, 2) 的路径不可达,因此返回 -1


这样是否满足你的要求?

提示

  • mn 的范围是 [1, 100]
  • 网格中的数值在 [0, 100] 范围内。

2.2 拓展解题代码

#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;/*** 基于力扣64题的变形题,详情请参考:https://smileyan.blog.csdn.net/article/details/142346755*/class Solution {
public:int minPathSum(vector<vector<int>>& grid) {int row = grid.size();int column = grid[0].size();vector<vector<int>> dp(row, vector<int>(column));dp[0][0] = grid[0][0];// 第一行每个点的最小路径int barricade = -1;for (int i = 1; i < column; i++) {if (dp[0][i - 1] == barricade || grid[0][i] == barricade) {dp[0][i] = barricade;} else {dp[0][i] = grid[0][i] + dp[0][i - 1];}}// 第一列每个点的最小路径for (int i = 1; i < row; i++) {if (dp[i - 1][0] == barricade || grid[i][0] == barricade) {dp[i][0] = barricade;} else {dp[i][0] = grid[i][0] + dp[i - 1][0];}}/** 对于 dp[i][k] 的计算规则为* dp[i][k] = min(dp[i - 1][k], dp[i][k - 1]) + grid[i][k]*/for (int i = 1; i < row; i++) {for (int k = 1; k < column; k++) {if (grid[i][k] == barricade || (dp[i - 1][k] == barricade && dp[i][k - 1] == barricade)) {dp[i][k] = barricade;} else if (dp[i - 1][k] == barricade) {dp[i][k] = dp[i][k - 1] + grid[i][k];} else if (dp[i][k - 1] == barricade) {dp[i][k] = dp[i - 1][k] + grid[i][k];} else {dp[i][k] = min(dp[i - 1][k], dp[i][k - 1]) + grid[i][k];}}}return dp[row - 1][column - 1];}
};int main() {Solution solution;vector<vector<int>> grid1 = {{1, 3, 1},{1, 5, 1},{4, 2, 1}};int result1 = solution.minPathSum(grid1);cout<<result1<<" -> 7"<<endl;vector<vector<int>> grid2 = {{1, 2, 3},{4, 5, 6}};int result2 = solution.minPathSum(grid2);cout<<result2<<" -> 12"<<endl;vector<vector<int>> grid3 = {{1, -1, 3},{4, -1, 6}};int result3 = solution.minPathSum(grid3);cout<<result3<<" -> -1"<<endl;vector<vector<int>> grid4 = {{1, -1, 3},{4, 1, 6}};int result4 = solution.minPathSum(grid4);cout<<result4<<" -> 12"<<endl;vector<vector<int>> grid5 = {{1, 3, 1},{1, 5, 2},{-1, 2, 1}};int result5 = solution.minPathSum(grid5);cout<<result5<<" -> 8"<<endl;vector<vector<int>> grid6 = {{1, 3, -1},{1, -1, 2},{-1, 2, 1}};int result6 = solution.minPathSum(grid6);cout<<result6<<" -> -1"<<endl;vector<vector<int>> grid7 = {{-1, 3, 1},{1, 1, 2},{1, 2, 1}};int result7 = solution.minPathSum(grid7);cout<<result7<<" -> -1"<<endl;vector<vector<int>> grid8 = {{1, 3, 1},{1, 1, 2},{1, 2, -1}};int result8 = solution.minPathSum(grid8);cout<<result8<<" -> -1"<<endl;return 0;
}

3. 总结

这道题应当与力扣第70题(爬楼梯)一样,作为动态规划的典型问题(热题100中多维动态规划类)。基于这道题面试官现场做了一个简单的调整,并不要求应聘者直接写代码求解出来,而是希望应聘者给出解决方案,并解释方案的可行性。

接下来的时间,还将围绕着这道题进行更多的摸索,动态规划是一个非常有意思的题:常常会因为阅读了 “参考答案” 而感到震惊。“怎么会这么简单”、“原来如此”。

感谢您的阅读、评论与点赞支持 ~ 感谢 ~

Smileyan
2024.09.21 23:48

http://www.lryc.cn/news/443715.html

相关文章:

  • Web后端开发技术:RESTful 架构详解
  • 【Fastapi】参数获取,json和query
  • 【Node.js】初识微服务
  • React项目实战(React后台管理系统、TypeScript+React18)
  • 【专题】2024中国生物医药出海现状与趋势蓝皮书报告合集PDF分享(附原数据表)
  • 【iOS】KVC
  • 【2024年华为杯研究生数学建模竞赛C题】完整论文与代码
  • svn回退到以前历史版本修改并上传
  • fiddler抓包07_抓IOS手机请求
  • Windows系统及Ubuntu系统安装Java
  • uni-data-select 使用 localdata 传入数据出现 不回显 | 下拉显示错误的 解决方法
  • 图解 TCP 四次挥手|深度解析|为什么是四次|为什么要等2MSL
  • DevExpress中文教程:如何将WinForms数据网格连接到ASP. NET Core WebAPI服务?
  • SpringBoot3核心特性-核心原理
  • Linux:RPM软件包管理以及yum软件包仓库
  • pod介绍与配置
  • 【Taro】初识 Taro
  • 【设计模式-备忘录】
  • 【数据结构】排序算法系列——快速排序(附源码+图解)
  • Arthas thread(查看当前JVM的线程堆栈信息)
  • Tomcat_WebApp
  • 代码随想录算法训练营Day10
  • 十个服务器中毒的常见特征及其检测方法
  • LeetCode 每周算法 6(图论、回溯)
  • Selenium元素定位:深入探索与实践
  • 前端开发——(1)使用vercel进行网页开发
  • 故障诊断│GWO-DBN灰狼算法优化深度置信网络故障诊断
  • 【工具】Windows|两款开源桌面窗口管理小工具Deskpins和WindowTop
  • 【Unity杂谈】iOS 18中文字体显示问题的调查
  • 后端-navicat查找语句(单表与多表)