LeetCode 2258. 逃离火灾:BFS

【LetMeFly】2258.逃离火灾

力扣题目链接:https://leetcode.cn/problems/escape-the-spreading-fire/

给你一个下标从 0 开始大小为 m x n 的二维整数数组 grid ,它表示一个网格图。每个格子为下面 3 个值之一:

  • 0 表示草地。
  • 1 表示着火的格子。
  • 2 表示一座墙,你跟火都不能通过这个格子。

一开始你在最左上角的格子 (0, 0) ,你想要到达最右下角的安全屋格子 (m - 1, n - 1) 。每一分钟,你可以移动到 相邻 的草地格子。每次你移动 之后 ,着火的格子会扩散到所有不是墙的 相邻 格子。

请你返回你在初始位置可以停留的 最多 分钟数,且停留完这段时间后你还能安全到达安全屋。如果无法实现,请你返回 -1 。如果不管你在初始位置停留多久,你 总是 能到达安全屋,请你返回 109 。

注意,如果你到达安全屋后,火马上到了安全屋,这视为你能够安全到达安全屋。

如果两个格子有共同边,那么它们为 相邻 格子。

 

示例 1:

输入:grid = [[0,2,0,0,0,0,0],[0,0,0,2,2,1,0],[0,2,0,0,1,2,0],[0,0,2,2,2,0,2],[0,0,0,0,0,0,0]]
输出:3
解释:上图展示了你在初始位置停留 3 分钟后的情形。
你仍然可以安全到达安全屋。
停留超过 3 分钟会让你无法安全到达安全屋。

示例 2:

输入:grid = [[0,0,0,0],[0,1,2,0],[0,2,0,0]]
输出:-1
解释:上图展示了你马上开始朝安全屋移动的情形。
火会蔓延到你可以移动的所有格子,所以无法安全到达安全屋。
所以返回 -1 。

示例 3:

输入:grid = [[0,0,0],[2,2,0],[1,2,0]]
输出:1000000000
解释:上图展示了初始网格图。
注意,由于火被墙围了起来,所以无论如何你都能安全到达安全屋。
所以返回 109

 

提示:

  • m == grid.length
  • n == grid[i].length
  • 2 <= m, n <= 300
  • 4 <= m * n <= 2 * 104
  • grid[i][j] 是 0 ,1 或者 2 。
  • grid[0][0] == grid[m - 1][n - 1] == 0

方法一:二分 + BFS

首先以所有的🔥为起点开始广度优先搜索,这样我们就能得到“火焰燃烧图”(🔥燃烧到某个坐标所需耗时)。

接着可以二分“👱的开局等待时长”。假设开局等待时间为 t t t,那么就从时间 t t t开始对👱能到达的位置进行广度优先搜索。

在对👱的广搜过程中:

  • 若搜索到了“安全屋”的位置:若“👱的到达耗时小于等于🔥的到达耗时”,则表示👱能等待时间 t t t后再出发
  • 否则(非安全屋位置):若“👱的到达耗时小于🔥的到达耗时”,则表示人能到达该位置

以上,即可。

  • 时间复杂度 O ( m n log ⁡ m n ) O(mn\log mn) O(mnlogmn),其中 s i z e ( g r i d ) = m × n size(grid)=m\times n size(grid)=m×n
  • 空间复杂度 O ( m n ) O(mn) O(mn)

AC代码

C++
class Solution {
private:
    int m, n;
    int direction[4][2] = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
    vector<vector<int>> fireTime;
    void debug(vector<vector<int>>& v) {
        for (auto& t : v) {
            for (auto& tt : t) {
                cout << tt << ' ';
            }
            cout << endl;
        }
    }

    void bfsFire(vector<vector<int>>& grid) {  // 计算火燃烧到每个位置时所需耗时并存入fireTime
        vector<vector<int>> graph = grid;
        fireTime = vector<vector<int>>(m, vector<int>(n, 1e9));
        queue<pair<int, int>> q;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (graph[i][j] == 1) {
                    q.push({i, j});
                    fireTime[i][j] = 0;
                }
            }
        }
        while (q.size()) {
            auto [x, y] = q.front();
            q.pop();
            for (int d = 0; d < 4; d++) {
                int tx = x + direction[d][0];
                int ty = y + direction[d][1];
                if (tx >= 0 && tx < m && ty >= 0 && ty < n && !graph[tx][ty]) {
                    graph[tx][ty] = 1;
                    fireTime[tx][ty] = fireTime[x][y] + 1;
                    q.push({tx, ty});
                }
            }
        }
    }

    bool check(vector<vector<int>>& grid, int t) {  // 其实是bfsPeople
        vector<vector<int>> peopleTime(m, vector<int>(n, 0)), graph(grid);
        peopleTime[0][0] = t;
        queue<pair<int, int>> q;
        q.push({0, 0});
        graph[0][0] = 2;
        while (q.size()) {
            auto [x, y] = q.front();
            q.pop();
            for (int d = 0; d < 4; d++) {
                int tx = x + direction[d][0];
                int ty = y + direction[d][1];
                int toTime = peopleTime[x][y] + 1;
                if (tx >= 0 && tx < m && ty >= 0 && ty < n && !graph[tx][ty]) {
                    graph[tx][ty] = 2;
                    if (tx == m - 1 && ty == n - 1 && toTime <= fireTime[m - 1][n - 1]) {
                        return true;
                    }
                    if (toTime < fireTime[tx][ty]) {
                        peopleTime[tx][ty] = toTime;
                        q.push({tx, ty});
                    }
                }
            }
        }
        return false;
    }
public:
    int maximumMinutes(vector<vector<int>>& grid) {
        m = grid.size(), n = grid[0].size();
        bfsFire(grid);
        int l = 0, r = n * m;
        int ans = -1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if (check(grid, mid)) {
                ans = mid;
                l = mid + 1;
            }
            else {
                r = mid - 1;
            }
        }
        return ans >= n * m ? 1e9 : ans;
    }
};
Python
# from typing import List
# from copy import deepcopy

class Solution:
    def __init__(self) -> None:
        self.direction = [[-1, 0], [1, 0], [0, -1], [0, 1]]
    
    def bfsFire(self, grid: List[List[int]]) -> None:
        fireTime = [[int(1e9)] * self.n for _ in range(self.m)]
        graph = deepcopy(grid)
        q = []
        for i in range(self.m):
            for j in range(self.n):
                if graph[i][j] == 1:
                    q.append((i, j))
                    fireTime[i][j] = 0
        while q:
            x, y = q[0]
            q = q[1:]
            for dx, dy in self.direction:
                tx, ty = x + dx, y + dy
                if tx >= 0 and tx < self.m and ty >= 0 and ty < self.n and not graph[tx][ty]:
                    q.append((tx, ty))
                    fireTime[tx][ty] = fireTime[x][y] + 1
                    graph[tx][ty] = 1
        self.fireTime = fireTime
    
    def check(self, grid: List[List[int]], t: int) -> bool:
        if t == 4:
            print(self.fireTime)
        peopleTime = [[0] * self.n for _ in range(self.m)]
        graph = deepcopy(grid)
        q = []
        q.append((0, 0))
        graph[0][0] = 2
        peopleTime[0][0] = t
        while q:
            x, y = q[0]
            q = q[1:]
            thisTime = peopleTime[x][y] + 1
            for dx, dy in self.direction:
                tx, ty = x + dx, y + dy
                if tx >= 0 and tx < self.m and ty >= 0 and ty < self.n and not graph[tx][ty]:
                    graph[tx][ty] = 2
                    if tx == self.m - 1 and ty == self.n - 1 and thisTime <= self.fireTime[-1][-1]:
                        return True
                    if thisTime < self.fireTime[tx][ty]:
                        peopleTime[tx][ty] = thisTime
                        q.append((tx, ty))
        return False

    def maximumMinutes(self, grid: List[List[int]]) -> int:
        self.m, self.n = len(grid), len(grid[0])
        self.bfsFire(grid)
        l, r = 0, self.m * self.n
        ans = -1
        while l <= r:
            mid = (l + r) // 2
            if self.check(grid, mid):
                ans = mid
                l = mid + 1
            else:
                r = mid - 1
        return int(1e9) if ans >= self.m * self.n else ans

if __name__ == '__main__':
    print(Solution().maximumMinutes(
        [[0,2,0,0,0,0,0],
         [0,0,0,2,2,1,0],
         [0,2,0,0,1,2,0],
         [0,0,2,2,2,0,2],
         [0,0,0,0,0,0,0]])
    )
    """
    [[6, ∞, 4, 3, 2, 1, 2],
     [5, 4, 3, ∞, ∞, 0, 1],
     [6, ∞, 2, 1, 0, ∞, 2],
     [7, 8, ∞, ∞, ∞, 14, ∞],
     [8, 9, 10, 11, 12, 13, 14]]
    """

方法二:数次BFS(无代码,可忽略)

其实这道题特殊的一点只有“安全屋”,只有安全屋这里🔥和👱可以同时到达。其他位置都必须保证👱比🔥严格地优先到达。

怎么到安全屋呢?要么从安全屋的左边,要么从安全屋的上面。因此先BFS一下得到🔥的“燃烧耗时图”,再按从 0 0 0时刻出发BFS👱。

最后判断一下安全屋及其左上两个位置👱🔥的到达时间,即可推断出👱在起点最多待多久。

2 15 > 2 × 1 0 4 2^{15}>2\times10^4 215>2×104,故方法一中也不会二分太多次。

同步发文于CSDN,原创不易,转载经作者同意后请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/134331955

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

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

相关文章

【无标题(PC+WAP)花卉租赁盆栽绿植类pbootcms站模板

(PCWAP)花卉租赁盆栽绿植类pbootcms网站模板 PbootCMS内核开发的网站模板&#xff0c;该模板适用于盆栽绿植网站等企业&#xff0c;当然其他行业也可以做&#xff0c;只需要把文字图片换成其他行业的即可&#xff1b; PCWAP&#xff0c;同一个后台&#xff0c;数据即时同步&…

web —— css(1)

Web —— css基础 1. CSS样式表2. CSS的三种引入方式3. CSS 语法4. CSS 选择器4.1 元素选择器4.2 类选择器4.3 ID选择器4.4 属性选择器4.5 后代选择器4.6 子元素选择器4.7 伪类选择器4.8 分组选择器 5. 颜色和字体6. 显示方式display7. 盒子模型7.1 盒子模型 - 外边距塌陷7.2 盒…

LED显示屏像素技术

LED显示屏的像素技术是LED显示屏的核心技术之一&#xff0c;它决定了显示屏的清晰度、亮度和色彩表现。以下是一些常见的LED显示屏像素技术&#xff1a; 直插式LED显示屏像素技术&#xff1a;该技术采用LED灯珠直接插入到电路板上的方式&#xff0c;通过电路板上的电路连接实现…

怎么设置代理IP进行网络爬取呢?代理访问网络如何设置?

在如今网络爬虫广泛应用的年代&#xff0c;很多时候我们都会遇到需要使用代理IP进行网络爬取的情况。代理IP可以帮助我们隐藏真实的IP地址&#xff0c;从而保护我们的隐私和安全。那么&#xff0c;怎么设置代理IP进行网络爬取呢&#xff1f;代理访问网络如何设置&#xff1f;下…

mysql explain type 枚举

explain 查看 sql 查询是否走索引。 其中 type 的枚举如下 类型说明system表只有一行&#xff08;系统表&#xff09;&#xff0c;这是 const 类型的特例const单表中的某个固定的值eq_ref使用唯一索引等值查找一个行ref使用非唯一索引查找所有匹配某个单个值的行fulltext使用…

R语言和jsonlite库编写代码示例

R语言和jsonlite库来下载的程序。 r # 导入jsonlite库 library(jsonlite) # 设置代理主机和端口 proxy_host <- "" proxy_port <- # 使用httr库创建一个对象 proxy <- create_proxy(proxy_host, proxy_port) # 使用httr库的GET方法下载网页内容 url <…

原型链污染攻击

想要很清楚了理解原型链污染我们首先必须要弄清楚原型链这个概念 可以看这篇文章&#xff1a;对象的继承和原型链 目录 prototype和__proto__分别是什么&#xff1f; 原型链继承 原型链污染是什么 哪些情况下原型链会被污染&#xff1f; 例题1&#xff1a;Code-Breaking 2…

【原理篇】四、自定义starter

文章目录 1、案例分析2、业务功能的实现3、中途调试4、开启定时任务打印报表5、引入属性配置类&#xff0c;写活业务参数配置6、拦截器7、开启yml提示功能 做一个记录系统访客独立IP访问次数的功能&#xff0c;并把它自定义成一个starter&#xff0c;实现&#xff1a;在现有项目…

阿里云中的云服务器的ubuntu中的vim没有显示行号

没有行号&#xff1a; 在终端输入命令&#xff1a; vim ~/.vimrc set nu

c语言总是有小问题,是练的少吗?

c语言总是有小问题&#xff0c;是练的少吗&#xff1f; 题主说我做c语言的题目时候&#xff0c;是有思路的并且可以按照想法写下来&#xff0c;大体上看没有问题&#xff0c;但是到运行的时候总是不过关。就需要很长的时间找出那个细微的错误&#xff0c;这种细微的错误怎么才能…

【C++】——类与对象(二)

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

基于element-plus定义表格行内编辑配置化

文章目录 前言一、新增table组件二、使用步骤 前言 在 基于element-plus定义表单配置化 基础上&#xff0c;封装个Element-plus的table表格 由于表格不同于form组件&#xff0c;需自定义校验器&#xff0c;以下组件配置了单个校验&#xff0c;及提交统一校验方法&#xff0c;且…

python核心编程速记【笔记迁移】

笔记速记 1.python非常注重缩进&#xff0c;这是它的显著特征之一。 2.import相当于头文件声明模块。 3.利用type函数 type(a)可以查看当前变量类型。 isinstance可以比较两个数据类型并返回一个布尔值。 4.这里面的可直接使用and和or作为一个函数 5.python的算法比较贴合…

新生儿疝气:原因、科普和注意事项

引言&#xff1a; 新生儿疝气是一种在婴儿中相对较常见的状况&#xff0c;很多新父母可能对这一现象感到困惑和焦虑。疝气发生时&#xff0c;内腹腔的一部分可能穿过腹壁的弱点&#xff0c;导致腹部出现凸起。本文将科普新生儿疝气的原因&#xff0c;提供相关信息&#xff0c;…

Jenkins CICD过程常见异常

1 Status [126] Exception when publishing, exception message [Exec exit status not zero. Status [126] 1.1 报错日志 SSH: EXEC: STDOUT/STDERR from command [/app/***/publish.sh] ... bash: /app/***/publish.sh: Permission denied SSH: EXEC: completed after 200…

PHP 使用递归方式 将其二维数组整合为层级树 其中层级id 为一个uuid的格式 造成的诡异问题 已解决

不啰嗦 直接上源代码 <?php function findChildren($list, $p_id){$r array();foreach ($list as $k > $item) {if ($item[fid] $p_id) {unset($list[$k]);$length count($r);$r[$length] $item;if ($t findChildren($list, $item[id])) {$r[$length][children] …

基于SSM的学生档案管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

android开发布局知识

插件开发的视频笔记&#xff1a;

跨境电商一定要做跨境独立站的6个原因!一键对接电商API接口瞬间拥有全球各大平台几十亿商品

跨境电商为什么要做独立站&#xff1f;它的优势又有哪一些&#xff1f; 如果说我们的企业是做BtoB的跨境电商&#xff0c;那今天这个内容一定要看仔细。 拥有了独立站你就是最高权力者&#xff0c;一切尽在自己掌控中&#xff01; 第一呢&#xff0c;独立站它就是我们自己做的…

IP行业API助力于网络分析和数据挖掘

引言 在当今数字化时代&#xff0c;数据成为了企业、科研机构和政府决策者的重要资源&#xff0c;而IP行业API则成为了数据分析及挖掘的工具之一。IP行业API是一种能够查询IP地址所属的行业分类信息的应用程序接口&#xff0c;它能够提供在网络分析、用户行为分析及大数据挖掘…