【每日一题】逃离火灾

文章目录

Tag

【二分答案】【BFS】【数组】【2023-11-09】


题目来源

2258. 逃离火灾


题目解读

现在有一个人在一个二维网格的左上角,坐标 (0, 0) 处,他想安全的到达位于网格右下角 (m-1, n-1) 处的安全屋,其中 m 为网格的行数,n 为网格的列数。

网格的每个格子中有以下三种数值:

  • 0 表示草地;
  • 1 表示着火的格子;
  • 2 表示一座墙,人和火都不能通过。

人每一分钟可以向相邻的格子行走,火可以向相邻的格子扩散,人和火都会被墙阻挡(也就是有墙的格子,人和火都无法到达)。现在需要你判断人在初始位置最多停留多长时间再出发可以安全到达安全屋。如果无法实现,请返回 -1。如果不管停留多长时间,人总是可以到达安全屋,请你返回 1 0 9 10^9 109


解题思路

方法一:二分枚举

我们可以使用二分枚举答案来解决该题。

为什么可以二分枚举答案?单调性如何保证?

如果人可以在初始位置停留 t 分钟,那么肯定可以停留至少 t 分钟;如果人不能在初始位置停留 t 分钟,那么可以停留的时间肯定不能超过 t 分钟。于是可以想到二分枚举答案,如果人可以在初始位置停留 t 分钟,那么接下来就在 t 的右侧进行枚举,否则在 t 的左侧进行枚举。我们通过函数 check() 来判断停留 t 分钟是否安全。

二分枚举答案的上限是什么?

如图,火可能要绕很多圈才能到达左上角,人可以在被火烧到的前一分钟出发。所以粗略估计,就用 m*n 当作二分的上限。

check() 如何实现?

假设当前二分枚举的答案是 t。不管是火的扩散还是人的行走都可以使用 BFS 来实现。

人在前往安全屋之前停留 t 分钟,在这 t 分钟内火向四周扩散。接着在每分钟内人先移动,火再移动,如果人遇到着火的格子那就跳过,不走这个格子。

如果,人最后可以到达安全屋,则说明答案至少为 t,否则答案小于 t

二分枚举逻辑代码

二分的下限 left0。上限 right 前面已经分析了是 mn。答案 res 初始化为 -1

[left, right] 中进行迭代二分,while(left <= right)

  • mid = (left + right) / 2
  • 如果 check(mid)true,则更新 res = midleft = mid + 1;否则更新 right = mid - 1
  • 最后返回 left

最终的答案还要比较一下 res 是否小于 m*n,如是返回 left,否则返回 1 0 9 10^9 109

实现代码

class Solution {
    const int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

public:
    bool check(vector<vector<int>>& grid, int t) {
        int m = grid.size(), n = grid[0].size();
        vector<vector<int>>on_fire(m, vector<int>(n));  // 记录着火的格子
        vector<pair<int, int>> f;                       // 两个数组来代替队列
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 1) {
                    on_fire[i][j] = 1;
                    f.emplace_back(i, j);               // 或者 f.push_back({i, j});
                }
            }
        }

        // 火扩散的 BFS
        auto spread_fire = [&]() {
            vector<pair<int, int>> nf;                  // f 和 nf 配合取代队列
            for (auto& [i, j] : f) {
                for (auto& [dx, dy] :dirs) {
                    int x = i + dx, y = j + dy;
                    if (0 <= x && x < m && 0 <= y && y < n && !on_fire[x][y] && grid[x][y] == 0) {
                        on_fire[x][y] = 1;
                        nf.emplace_back(x, y);
                    }
                }
            }
            f = move(nf);
        };

        // t 分钟内火向四周扩散
        while (t -- && !f.empty()) {
            spread_fire();
        }

        if (on_fire[0][0]) return false;                  // 初始位置着火

        // 人和火先后扩散
        vector<vector<int>> vis(m, vector<int>(n));       // 防止人重复走同一个格子
        vis[0][0] = 1;
        vector<pair<int, int>> q{{0, 0}};
        while (!q.empty()) {
            vector<pair<int, int>> nq;
            for (auto& [i, j] : q) {
                if (on_fire[i][j]) continue;
                for (auto& [dx, dy] : dirs) {
                    int x = i + dx, y = j + dy;
                    if (0 <= x && x < m && 0 <= y && y < n && !on_fire[x][y] && grid[x][y] == 0 && !vis[x][y]) {
                        if (x == m - 1 && y == n - 1) {
                            return true;
                        }
                        vis[x][y] = 1;
                        nq.emplace_back(x, y);
                    }
                }    
            }
            q = move(nq);
            spread_fire();
        }
        return false; 
    }

    int maximumMinutes(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        int left = 0, right = m * n;
        int res = -1;
        while (left <= right) {
            int mid = (left + right) >> 1;
            if (check(grid, mid)) {
                res = mid;
                left = mid + 1;
            }
            else {
                right = mid - 1;
            }
        }
        return res < m * n ? res : 1e9;
    }
};

复杂度分析

时间复杂度: O ( m n l o g m n ) O(mnlogmn) O(mnlogmn) m m m n n n 分别为 grid 的行数和列数,二分枚举 O ( l o g m n ) O(logmn) O(logmn) 次,每次 check() 的时间为 O ( m n ) O(mn) O(mn)

空间复杂度: O ( m n ) O(mn) O(mn)

写在最后

如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。

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

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

相关文章

SpringCache(Redis)

一、springcache是什么 springcache是spring的缓存框架&#xff0c;利用了AOP&#xff0c;实现了基于注解的缓存功能&#xff0c;并且进行了合理的抽象&#xff0c;业务代码不用关心底层是使用了什么缓存框架&#xff0c;只需要简单地加一个注解&#xff0c;就能实现缓存功能了…

pytorch中常用的损失函数

1 损失函数的作用 损失函数是模型训练的基础&#xff0c;并且在大多数机器学习项目中&#xff0c;如果没有损失函数&#xff0c;就无法驱动模型做出正确的预测。 通俗地说&#xff0c;损失函数是一种数学函数或表达式&#xff0c;用于衡量模型在某些数据集上的表现。损失函数在…

计算机网络期末复习-Part2

1、网络应用程序体系结构 &#xff08;1&#xff09;客户端/服务器&#xff08;C/S&#xff09;体系结构&#xff1a; 客户端/服务器&#xff08;C/S&#xff09;应用程序&#xff1a; Web浏览器与Web服务器&#xff1a;当您使用Web浏览器&#xff08;客户端&#xff09;访问…

Scala爬虫如何实时采集天气数据?

这是一个基本的Scala爬虫程序&#xff0c;使用了Scala的http library来发送HTTP请求和获取网页内容。在爬取天气预报信息时&#xff0c;我们首先需要创建一个代理对象proxy&#xff0c;并将其用于发送HTTP请求。然后&#xff0c;我们使用http库的GET方法获取网页内容&#xff0…

linux修改rocketmq的日志文件位置

文章目录 &#x1f50a;修改rocketmq的日志文件位置&#x1f4d5;原来的文件&#x1f4cc;修改后文件&#x1f4c7;rocketmq中的Rocketmq_client.log文件在配置文件中改不了 需要在代码logback文件中进行修改&#x1f58a;️最后总结 &#x1f50a;修改rocketmq的日志文件位置 …

【Linux】 awk命令使用

AWK 是一种处理文本文件的语言&#xff0c;是一个强大的文本分析工具。 之所以叫 AWK 是因为其取了三位创始人 Alfred Aho&#xff0c;Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。 语法 awk [选项] [文件] awk [选项] [程序] [文件] awk命令 -Linux手…

cookie 里面都包含什么属性?

结论先行&#xff1a; Cookie 中除了名称和值外&#xff0c;还有几个比较常见的&#xff0c;例如&#xff1a; Domain 域&#xff1a;指定了 cookie 可以发送到哪些域&#xff0c;只有发送到指定域或其子域的请求才会携带该cookie&#xff1b; Path 路径&#xff1a;指定哪些…

Spring Boot 3系列之-启动类详解

Spring Boot是一个功能强大、灵活且易于使用的框架&#xff0c;它极大地简化了Spring应用程序的开发和部署流程&#xff0c;使得开发人员能够更专注于业务逻辑的实现。在我们的Spring Boot 3系列之一&#xff08;初始化项目&#xff09;文章中&#xff0c;我们使用了Spring官方…

gitlab-ce-12.3.5 挖矿病毒及解决方案

前言 最近发现在使用gitlab提交代码的时候总是失败&#xff0c;一访问gitlab还时常报503&#xff0c;于是使用 top 命令查看了内存占用情况&#xff0c;发现了一个git进程内存使用了2.3g&#xff0c;cpu还一直占用300-400%&#xff0c; 以前不知道gitlab还有病毒&#xff0c;只…

[论文阅读]PV-RCNN++

PV-RCNN PV-RCNN: Point-Voxel Feature Set Abstraction With Local Vector Representation for 3D Object Detection 论文网址&#xff1a;PV-RCNN 论文代码&#xff1a;PV-RCNN 简读论文 这篇论文提出了两个用于3D物体检测的新框架PV-RCNN和PV-RCNN,主要的贡献如下: 提出P…

ubuntu 安装redis详细教程

下载redis安装包 链接如下&#xff1a; http://redis.io/download 本例版本为&#xff1a;redis-7.2.3.tar.gz 下载安装包到目录/opt下&#xff0c;路径可修改&#xff0c;本例为/opt wget https://github.com/redis/redis/archive/7.2.3.tar.gz 解压安装包&#xff0c;并…

解决 SSLError: HTTPSConnectionPool(host=‘huggingface.co‘, port=443)

看我的回答&#xff1a; https://github.com/huggingface/transformers/issues/17611#issuecomment-1794486960 能问这个问题的都是网络不太好的&#xff0c;你懂的&#xff0c;所以答案全是解决网络的。 得益于这个回答&#xff1a;#17611 (comment) 看了一下代码&#xf…

基于ssm的校园快递物流管理系统(java+jsp+ssm+javabean+mysql+tomcat)

博主24h在线&#xff0c;想要源码文档部署视频直接私聊&#xff0c;9.9拿走&#xff01; 基于javawebmysql的ssm校园快递物流管理系统(javajspssmjavabeanmysqltomcat) 运行环境&#xff1a; Java≥8、MySQL≥5.7、Tomcat≥8 开发工具&#xff1a; eclipse/idea/myeclipse/s…

万物社用户运营工具:无代码开发下的电商平台和CRM集成

简介&#xff1a;万物社与集简云的引领式连接 万物社&#xff0c;隶属于厦门头号云信息科技有限公司&#xff0c;是一家专注于互联网和相关服务的企业。在日常的业务运营中&#xff0c;万物社通过与集简云的无代码集成&#xff0c;实现了业务流程的自动化和智能化&#xff0c;…

Linux系统下数据同步服务RSYNC

一、RSYNC概述 1、什么是rsync rsync的好姐妹 sync 同步&#xff1a;刷新文件系统缓存&#xff0c;强制将修改过的数据块写入磁盘&#xff0c;并且更新超级块。 async 异步&#xff1a;将数据先放到缓冲区&#xff0c;再周期性&#xff08;一般是30s&#xff09;的去同步到磁…

【Git】安装和常用命令的使用与讲解及项目搭建和团队开发的出现的问题并且给予解决

目录 Git的简介 介绍 Git的特点及概念 Git与SVN的区别 图解 ​编辑 命令使用 安装 使用前准备 搭建项目环境 ​编辑 团队开发 Git的简介 介绍 Git 是一种分布式版本控制系统&#xff0c;是由 Linux 之父 Linus Torvalds 于2005年创建的。Git 的设计目标是为了更好地管…

图文并茂解读联合索引底层存储结构及索引查找过程

文章目录 前言版本数据准备SQL数据创建结果有无联合索引执行情况无联合索引存在联合索引 底层存储结构查询过程最左匹配原则查询过程解析 联合索引优势支持复杂查询索引覆盖查询提高排序和分组性能减少索引数量 使用建议联合索引的列顺序十分重要建议能使用联合索引尽量使用联合…

Mybatis-Plus同时使用逻辑删除和唯一索引的问题及解决办法

1 问题背景 在开发中&#xff0c;我们经常会有逻辑删除和唯一索引同时使用的情况。但当使用mybatis plus时&#xff0c;如果同时使用逻辑删除和唯一索引&#xff0c;会报数据重复Duplicate entry的问题。 举例来说&#xff0c;有表user&#xff0c;建立唯一索引&#xff08;u…

Docker本地部署Drupal并实现公网访问

文章目录 前言1. Docker安装Drupal2. 本地局域网访问3 . Linux 安装cpolar4. 配置Drupal公网访问地址5. 公网远程访问Drupal6. 固定Drupal 公网地址 前言 Dupal是一个强大的CMS&#xff0c;适用于各种不同的网站项目&#xff0c;从小型个人博客到大型企业级门户网站。它的学习…

ZYNQ_project:key_led

条件里是十进制可以不加进制说明&#xff0c;编译器默认是10进制&#xff0c;其他进制要说明。 实验目标&#xff1a; 模块框图&#xff1a; 时序图&#xff1a; 代码&#xff1a; include "para.v"module key_filter (input wire …