leetcode 2617. 网格图中最少访问的格子数【单调栈优化dp+二分】

原题链接:2617. 网格图中最少访问的格子数

题目描述:

给你一个下标从 0 开始的 m x n 整数矩阵 grid 。你一开始的位置在 左上角 格子 (0, 0) 。

当你在格子 (i, j) 的时候,你可以移动到以下格子之一:

  • 满足 j < k <= grid[i][j] + j 的格子 (i, k) (向右移动),或者
  • 满足 i < k <= grid[i][j] + i 的格子 (k, j) (向下移动)。

请你返回到达 右下角 格子 (m - 1, n - 1) 需要经过的最少移动格子数,如果无法到达右下角格子,请你返回 -1 。

输入输出描述:

示例 1:

输入:grid = [[3,4,2,1],[4,2,3,1],[2,1,0,0],[2,4,0,0]]
输出:4
解释:上图展示了到达右下角格子经过的 4 个格子。

示例 2:

输入:grid = [[3,4,2,1],[4,2,1,1],[2,1,1,0],[3,4,1,0]]
输出:3
解释:上图展示了到达右下角格子经过的 3 个格子。

示例 3:

输入:grid = [[2,1,0],[1,0,0]]
输出:-1
解释:无法到达右下角格子。

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 10^5
  • 1 <= m * n <= 10^5
  • 0 <= grid[i][j] < m * n
  • grid[m - 1][n - 1] == 0

解题思路:

这个题目我觉得出的非常好,一个非常经典的单调栈优化dp,这个题目首先每一步只能往右或者下走,很容易看出是dp,但是如果直接暴力dp,对于每个位置每次最多从n或者m个位置转移过来,那么时间复杂度就是O(n*m*(n+m)),这个时间复杂度就有点高了,我们需要考虑优化,我觉得有意思的就是这个优化,很容易可以看出需要维护的是某个区间的最小值,那么最容易想到的就是滑动窗口优化,但是这里左窗口虽然是单调减小的,但是右窗口的单调性不稳定,所以这个时候如果使用滑动窗口优化就不方便了,实际上我们考虑单调栈进行维护,我们考虑倒序枚举,在单调栈中维护一个从栈底到栈顶单调递增的序列,我们需要对每一行和每一列都维护一个单调栈,我们需要找到当前行中<=j+grid[i][j]的中的最小值,也就是需要找到从栈底到栈顶第一个列位置<=j+grid[i][j]的位置的值,我们直接在单调栈上进行二分即可,对于列做同样的处理即可。

通过上面的分析,这个问题就可以解决了,但是我写出了一个bug找了很久才找出来,那就是在单调栈维护的过程中,我们需要将行和列都更新完f[i][j]之后,才能进行去维护单调栈,因为如果我们只更新完行就去维护单调栈,但是后面更新列的时候f[i][j]又变小了,那么会导致行单调栈中的还有一些元素需要删除的没有删掉,导致后面某些位置计算到了一些错误的答案,对于只更新完列就去维护单调栈同样会出现这种错误,所以我们只有当行和列都更新完,才能去维护单调栈,这个错误我是真的看了好久才看出来,开始根本没有注意到这一点,就是一直是错的,但是我又确信我的思路应该是没有什么问题的,也就是突然之间就灵机一动意识到了这一点,不然我可能还真很难找到这个错误。

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

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

cpp代码如下:

class Solution {
public:
    int minimumVisitedCells(vector<vector<int>>& grid) {
        int n=grid.size(),m=grid[0].size();
        vector<int>row[n],col[m];
        vector<vector<int>>f(n,vector<int>(m,1e9));
        f[n-1][m-1]=1;

        for(int i=n-1;i>=0;i--)
            for(int j=m-1;j>=0;j--)
            {
                int l=0,r=row[i].size()-1;
                while(l<r){
                    int mid=l+r>>1;
                    if(row[i][mid]<=j+grid[i][j])r=mid;
                    else l=mid+1;
                }
                if(r>=0 && row[i][r]<=j+grid[i][j]){
                    f[i][j]=min(f[i][j],f[i][row[i][r]]+1);
                }

                l=0,r=col[j].size()-1;
                while(l<r){
                    int mid=l+r>>1;
                    if(col[j][mid]<=i+grid[i][j])r=mid;
                    else l=mid+1;
                }
                if(r>=0 && col[j][r]<=i+grid[i][j]){
                    f[i][j]=min(f[i][j],f[col[j][r]][j]+1);
                }

                //上面行和列都更新完才来维护单调栈
                while(row[i].size() && f[i][row[i].back()]>=f[i][j]){
                    row[i].pop_back();
                }
                while(col[j].size() && f[col[j].back()][j]>=f[i][j]){
                    col[j].pop_back();
                }
                row[i].push_back(j);
                col[j].push_back(i);
            }
        if(f[0][0]==1e9)return -1;
        return f[0][0];
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/478415.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式开发--STM32G431RBTx-定时器中断流水灯

嵌入式开发–STM32G431RBTx-定时器中断流水灯 定时器工作原理 如图有反映stm32g431的定时器资源。 共10个定时器 定时器定时器类型个数TIM6&#xff0c;7基本定时器2TIM2&#xff0c;3&#xff0c;4全功能通用定时器3TIM15&#xff0c;16&#xff0c;17通用定时器(只有1或2个…

Linux_开发工具_yum_vim_gcc/g++_gdb_make/makefile_进度条_git_2

文章目录 一、Linux软件包管理器yum1. centos7 中安装软件方式2.安装&#xff0c;卸载&#xff0c;查看3.yum源4.安装lrzsz5.安装扩展源 二、Linux编辑器-vim1.安装vim2.vim的三种模式3.命令模式-文本批量化操作4.vim配置 三、Linux编译器-gcc/g使用1.安装2.gcc如何完成1、 预处…

SpringBoot3使用响应Result类返回的响应状态码为406

Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: No acceptable representation] 解决方法&#xff1a;Result类上加上Data注解

【算法刷题】Day33

文章目录 1. 最长湍流子数组题干&#xff1a;算法原理&#xff1a;1. 状态表示&#xff1a;2. 状态转移方程3. 初始化4. 填表顺序5. 返回值 代码&#xff1a; 2. 最长递增子序列题干&#xff1a;算法原理&#xff1a;1. 状态表示&#xff1a;2. 状态转移方程3. 初始化4. 填表顺…

链表递归-leetcode两两交换相邻链表中的结点

两两交换相邻链表中的结点 题目&#xff1a; 给定一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后的链表。 你不能只是单纯的改变节点内部的值&#xff0c;而是需要实际的进行节点交换。 示例1 输入&#xff1a;head [1,2,3,4] 输出&#xff1a;[2,1…

文件怎么做扫码预览?创建文件活码的步骤有哪些?

现在文件可以通过扫描二维码的方式来获取&#xff0c;与传统的通过聊天软件来传输相比&#xff0c;二维码方式的应用更加的方便&#xff0c;其他人只需要通过扫描一张二维码就可以在手机上浏览或者下载文件&#xff0c;通过手机就可以预览、存储。 文件二维码的制作方法也很简…

C语言牛客网刷题

1.最大公约数和最小公倍数的组合问题 &#xff08;1&#xff09;在调试的过程中涉及到很大的数据&#xff0c;我们我们在定义变量的时候定义为long long类型 &#xff08;2&#xff09;这个里面我们自定义了max2用来求最大公约数&#xff0c;min2用来求最小公倍数 &#xff0…

稀碎从零算法笔记Day23-LeetCode:翻转二叉树

题型&#xff1a;链表、二叉树 链接&#xff1a;226. 翻转二叉树 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 这道题适合就着样例来做 题目样例 …

sqlite3 交叉编译

#1.下载源码并解压 源码路径如下&#xff0c;下载autoconf版本 SQLite Download Page 解压 tar -zxvf sqlite-autoconf-3450200.tar.gz cd sqlite-autoconf-3450200 mkdir build # 2. 配置源代码 # 假设你已经安装了交叉编译工具链&#xff0c;如gcc-arm-linux-gnueabih…

2024年React初学者入门路线指南

在这篇文章中&#xff0c;我们一步一步探索了如何从零基础开始学习React&#xff0c;并逐渐成长为一名初级开发者。通过理解基础概念、实践构建静态和动态项目&#xff0c;最终发展到创建复杂的应用程序并加入到个人作品集中&#xff0c;您现在已经准备好迈向React开发者的职业…

Vue3:网页项目中路由的设计和配置

为了避免我每次建项目配路由的时候都回去翻网课&#xff0c;打算整一博客 路由设计 不同网页的路由设计思路基本相同&#xff0c;分为一级路由和二级路由&#xff0c;基本设计思路如下图 以我之前做过的招新系统管理端为例&#xff0c;可设计出如下路由 路由配置 还是以招新系…

背包问题总结

背包问题总结 一、01背包 原题链接&#xff1a;2. 01背包问题 - AcWing题库 思路分析 dp问题最重要的是状态转移方程。那么我们首先来定义一下状态&#xff1a; dp[i][j] 表示前 i 个物品&#xff0c;背包容量不超过 j 时的最大价值。 那么要怎么更新状态呢&#xff1f; …

Windows server 2008 R2共享文件配置和web网站的发布 试题一(Windows部分)

Windows server 2008 R2共享文件配置和web网站的发布 试题一&#xff08;Windows部分&#xff09; 设置虚拟机与本机互通设置虚拟机IP关闭虚拟机防火墙设置本机IP测试本机与虚拟机是否可以互通 开启文件共享function discovery resource publication服务的开启SSDP Discovery服…

SpringBoot-03 | SpringBoot自动配置

SpringBoot-03 | SpringBoot自动配置 原理分析代码示例源码剖析SpringBootConfiguration&#xff1a;组合注解&#xff0c;标记当前类为配置类ComponentScanEnableAutoConfigurationImport加载spring.factoriesrun初始化加载spring.factoriesspring.factories中的钩子类 网上盗…

【最后2天】京东云游戏云服务器0门槛抽奖送!云服务器选购推荐 京东云 阿里云 腾讯云对比 幻兽帕鲁 雾锁王国 省钱学生党

好消息&#xff1a;抽奖活动开启&#xff01;时间&#xff1a;3月17日——3月24日 最高奖品&#xff1a;16G 6个月&#xff1b;32G 3个月 抽奖规则&#xff1a;B站点赞评论关注即可参与抽奖&#xff0c;3.24日公布获奖名单。 抽奖地址&#xff1a; 【首次抽奖】16G、32G免费…

每日学习笔记:C++ STL 容器的杂谈

三种自定义STL容器 string作为STL容器 C风格数组作为STL容器 C11以后 C11以前 容器元素类型是引用 使用智能指针存储元素 使用引用外覆器 各容器使用时机 如何分别用两种不同的排序准则来存储同批数据&#xff1f; 解决方案&#xff1a;将容器元素改为智能指针即可。 根据排…

CentOS/RHEL 6.5 上 NFS mount 挂起kernel bug

我本身有四台机器做WAS集群&#xff0c;挂载nfs&#xff0c;其中随机一台客户端计算机端口关闭释放将进入不良状态&#xff0c;对 NFSv4 挂载的任何访问都将挂起&#xff08;例如“ls&#xff0c;cd 或者df均挂起”&#xff09;。这意味着没有人并且所有需要访问共享的用户进程…

【笔记】以论文发表形式通俗理解 TCP/IP模型

【笔记】以论文发表形式通俗理解 TCP/IP模型 前言TCP/IP模型理论通俗理解 前言 在网络基础学习过程中&#xff0c;以前只对TCP/IP理解个字面&#xff0c;网上查一下能知道个字面意思&#xff0c;但是连起来到底是什么意思&#xff0c;还是一知半解的&#xff0c;停留在表面&am…

实型数据详解

1 实型常量的表示方法 实数(real number)又称浮点数(floating-point number)。实数有两种表示形式: (1)十进制小数形式。它由数字和小数点组成(注意必须有小数点)。.123、123.、123.0、0.0都是十进制小数形式。 (2)指数形式。如123e3或123E3都代表123x103。但注意字母e(或E)…

gdb和makefile的讲解

Linux调试器-gdb使用 gdb可以用于Linux环境下的程序的调试&#xff0c;就例如vs环境下的打断点&#xff0c;然后逐步分析语句等 1 gdb的背景 程序的发布方式有两种&#xff0c;debug模式和release模式 我们在使用vs21时大家都清楚&#xff0c;release版本是不能被调试的&…