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

news2024/9/22 4:57:50

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, 2],
  [4, 2, 1]
]
输出
7
解释

最优路径为 (0,0) -> (1,0) -> (2,0) -> (2,1) -> (2,2),路径费用为 1 + 1 + 4 + 2 + 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.coloradmin.cn/o/2154167.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库提权【笔记总结】

文章目录 UDF提权以有webshell只有数据库权限条件复现msf工具sql语句提权 MOF提权前言条件复现msf工具php脚本提权 sqlserver提权前言条件xp_cmdshell提权复现 沙盒提权介绍复现 Oracle提权靶场搭建执行任意命令复现 通过注入存储过程提权&#xff08;低权限提升至DBA&#xff…

HTML-DOM模型

1.DOM模型 window对象下的document对象就是DOM模型。 DOM描绘了一个层次化的节点树&#xff0c;每一个节点就是一个html标签&#xff0c;而且每一个节点也是一个DOM对象。 2.操作DOM 2.1.获取DOM对象常用方法 获取DOM对象的常用方法有如下几种&#xff1a; getElementById(…

Linux入门学习:Git

文章目录 1. 创建仓库2. 仓库克隆3. 上传文件4. 相关问题4.1 git进程阻塞4.2 git log4.3 上传的三个步骤在做什么4.4 配置邮箱/用户名 本文介绍如何在Linux操作系统下简单使用git&#xff0c;对自己的代码进行云端保存。 1. 创建仓库 &#x1f539;这里演示gitee的仓库创建。…

Linux 基础IO 1

文件操作 基础IO 在程序中若需要读取文件数据或者将数据永久存入需要使用文件因为程序的产生的数据都是在内存中的&#xff0c;只要关闭程序就会释放掉不会&#xff0c;所以在一些程序中我们难免需要对文件进程操作。无论我们是存入数据还是提取数据前提是有这个数据并清楚它…

VGG16模型实现新冠肺炎图片多分类

1. 项目简介 本项目的目标是通过深度学习模型VGG16&#xff0c;实现对新冠肺炎图像的多分类任务&#xff0c;以帮助医疗人员对患者的影像进行快速、准确的诊断。新冠肺炎自爆发以来&#xff0c;利用医学影像如X光和CT扫描进行疾病诊断已成为重要手段之一。随着数据量的增加&am…

联想(lenovo) 小新Pro13锐龙版(新机整理、查看硬件配置和系统版本、无线网络问题、windows可选功能)

新机整理 小新pro13win10新机整理 查看硬件配置和系统版本 设置-》系统-》系统信息 无线网络问题 部分热点可以&#xff0c;部分不可以 问题&#xff1a;是因为自己修改了WLAN的IP分配方式为手动分配&#xff0c;导致只能在连接家里无线网的时候可以&#xff0c;连接其他…

51单片机——独立按键

一、独立按键对应单片机P3管脚&#xff0c;如图 二、按键点亮LED灯 #include <STC89C5xRC.H> void main() { while(1) { if(P300) { P200; } else { P201; } } } 当按键为0时&#xff0c;代表按下&#xff0c;所以当P30按下时&#xff0c;让P20&#xff1d;0&#…

Java面试篇基础部分-ReentrantLock详解

ReentrantLock 是继承了Lock接口,并且实现了再接口中定义的方法,属于一个可重入的独占锁。ReentrantLock 通过自定义队列同步器(Abstract Queued Synchroinzed,AQS)来实现锁的获取与释放。   那么什么是独占锁呢?独占锁就是指这个锁在同一时刻只能被一个线程所获取到,…

2024年最新网络协议分析器Wireshark抓包详细教程(更新中)

网络协议分析器 Wireshark 安装 Wireshark 是一个功能强大的网络协议分析器&#xff0c;早期叫作 Ethereal。它主要用于捕获网络数据包&#xff0c;并对这些数据包进行详细的解析和分析&#xff0c;帮助用户深入了解网络通信的细节。它支持多种网络协议&#xff0c;并提供详细…

VM虚拟机下载以及激活

传统的官网已经找不到下载了&#xff0c;这里我将下载好的放在阿里云盘&#xff0c;百度云盘太慢了&#xff0c;懂得都得 阿里云盘分享 下载好了后会是一个exe文件&#xff0c;直接双击运行就可 下载无脑下一步即可&#xff0c;这里不做介绍 下载好了后&#xff0c;需要密钥这里…

如何搭建IP代理池:从零开始的详细指南

在网络应用中&#xff0c;IP代理池是一种非常实用的工具&#xff0c;尤其是在需要大量IP地址进行网络请求时&#xff0c;例如网络爬虫、数据抓取和分布式系统等。通过搭建IP代理池&#xff0c;你可以有效地管理和分配IP地址&#xff0c;避免单一IP地址被封锁&#xff0c;提高网…

高效编程的利器 Jupyter Notebook

目录 前言1. Jupyter Notebook简介1.1 功能特点1.2 使用场景 2. 不同编程工具的对比与效率提升2.1 VS Code&#xff1a;灵活且轻量的代码编辑器2.2 PyCharm&#xff1a;面向专业开发者的集成开发环境2.3 Git&#xff1a;高效协作的版本控制工具2.4 Jupyter Notebook 和 VS Code…

【算法题】63. 不同路径 II-力扣(LeetCode)-”如果起点有障碍物,那么便到不了终点“

【算法题】63. 不同路径 II-力扣(LeetCode)-”如果起点有障碍物&#xff0c;那么便到不了终点“ 1.题目 下方是力扣官方题目的地址 63. 不同路径 II 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下…

【Godot4.x】Mesh相关知识总结

概述 很早之前发布过一篇关于几何体程序生成的文章&#xff0c;当时对于三角面和网格的构造其实还没有特别深入的认识&#xff0c;直到自己脑海里想到用二维数组和点更新的方式构造2D类型的多边形Mesh结构&#xff0c;也意识到在Godot中其实Mesh不仅是3D网格&#xff0c;也可以…

LeetCode 每周算法 6(图论、回溯)

LeetCode 每周算法 6&#xff08;图论、回溯&#xff09; 图论算法&#xff1a; class Solution: def dfs(self, grid: List[List[str]], r: int, c: int) -> None: """ 深度优先搜索函数&#xff0c;用于遍历并标记与当前位置(r, c)相连的所有陆地&…

uni-data-select 使用 localdata 传入数据出现 不回显 | 下拉显示错误的 解决方法

目录 1. 问题所示2. 正确Demo3. 下拉显示错误(Bug复现)4. 下拉不回显(Bug复现)1. 问题所示 uni-app的下拉框uni-data-select 使用 localdata 传入数据 主要总结正确的Demo以及复现一些Bug 数据不回显数据不显示下拉选项2. 正确Demo 详细的基本知识推荐阅读:uni-app中的…

Codeforces Round 974 (Div. 3) A-F

封面原图 画师礼島れいあ 下午的ICPC网络赛的难受一晚上全都给我打没了 手速拉满再加上秒杀线段树 这场简直了啊 唯一可惜的是最后还是掉出了1000名 一把上蓝应该没啥希望了吧 A - Robin Helps 题意 侠盗罗宾因劫富济贫而闻名于世 罗宾遇到的 n n n 人&#xff0c;从 1 s …

springMvc的初始配置

基础文件结构(toWeb插件) 1.导入对应依赖 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"ht…

BLE 设备丢包理解

前言 个人邮箱&#xff1a;zhangyixu02gmail.com在学习 BLE 过程中&#xff0c;总能听到 “丢包” 一词&#xff0c;但是我查阅资料又发现&#xff0c;有大佬说&#xff0c;ATT所有命令都是“必达”的&#xff0c;不存在所谓的“丢包”。而且我发现&#xff0c;在宣传 BLE 产品…

tcp、udp通信调试工具Socket Tool

tcp、udp通信调试工具Socket Tool ]