LeetCode 1162. As Far from Land as Possible【多源BFS】中等

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。

为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库:https://github.com/memcpy0/LeetCode-Conquest。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。

由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。

你现在手里有一份大小为 n x n 的 网格 grid,上面的每个 单元格 都用 01 标记好了。其中 0 代表海洋,1 代表陆地。

请你找出一个海洋单元格,这个海洋单元格到离它最近的陆地单元格的距离是最大的,并返回该距离。如果网格上只有陆地或者海洋,请返回 -1

我们这里说的距离是「曼哈顿距离」( Manhattan Distance):(x0, y0)(x1, y1) 这两个单元格之间的距离是 |x0 - x1| + |y0 - y1|

示例 1:

输入:grid = [[1,0,1],[0,0,0],[1,0,1]]
输出:2
解释: 
海洋单元格 (1, 1) 和所有陆地单元格之间的距离都达到最大,最大距离为 2

示例 2:

输入:grid = [[1,0,0],[0,0,0],[0,0,0]]
输出:4
解释:
海洋单元格 (2, 2) 和所有陆地单元格之间的距离都达到最大,最大距离为 4

提示:

  • n == grid.length
  • n == grid[i].length
  • 1 <= n <= 100
  • grid[i][j] 不是 0 就是 1

本题与542. 01 Matrix相同。

解法 多源BFS

这里不是求某一个海洋区域到陆地区域的最短路,而是求所有的海洋区域到陆地区域这个「点集」的最短路。显然这不是一个「单源」最短路问题(SSSP)。在我们学习过的最短路算法中,求解 SSSP 问题的方法有 Dijkstra 算法和 SPFA算法,而求解任意两点之间的最短路一般使用 Floyd 算法。那我们在这里就应该使用 Floyd 算法吗?

要考虑这个问题,我们需要分析一下这里使用 Floyd 算法的时间复杂度。我们知道在网格图中求最短路,每个区域(格子)相当于图中的顶点,而每个格子和上下左右四个格子的相邻关系相当于边,我们记顶点的个数为 V V V ,Floyd 算法的时间复杂度为 O ( V 3 ) O(V^3) O(V3) ,而这里 V = n 2 V = n^2 V=n2 ,所以 O ( V 3 ) = O ( n 6 ) O(V^3) = O(n^6) O(V3)=O(n6) ,显然是不现实的。

考虑 SSSP 是求一个源点到一个点集中所有点的最短路,而这个问题的本质是求某个点集到另一个点集中所有点的最短路,即「多源最短路」,我们只需要对 Dijkstra 算法或者 SPFA 算法稍作修改。这里以 Dijkstra 算法为例,我们知道堆优化的 Dijkstra 算法实际上是 BFS 的一个变形把 BFS 中的队列变成了优先队列,在拓展新状态的时候加入了松弛操作。Dijkstra 的堆优化版本第一步是源点入队,我们只需要把它改成源点集合中的所有的点入队,就可以实现求「多源最短路」。

思考:为什么?
因为我们这样做相当于建立了一个超级源点 S S S这个点与源点集中的 s 0 , s 1 , s 2 ⋯ s ∣ V ∣ s_0, s_1, s_2 \cdots s_{|V|} s0,s1,s2sV 都有边,并且权都为 0 0 0 。这样求源点集到目标点集的最短路,就变成了求超级源点 S S S 到它们的最短路,于是又转化成了 SSSP 问题。

继续思考:海洋区域和陆地区域,应该哪一个作为源点集?
也许你分析出「我们需要找一个海洋区域,满足它到陆地的最小距离是最大」会把海洋区域作为源点集。考虑后续的实现,我们知道 Dijkstra 中一个 d d d 数组用来维护当前源点集到其他点的最短路,而对于源点集中的任意一个点 s s s d [ s x ] [ s y ] = 0 d[s_x][s_y] = 0 d[sx][sy]=0 ,这很好理解,源点到源点的最短路就是 0 0 0 。如果我们把海洋区域作为源点集、陆地区域作为目标点集,假设 t t t 是目标点集中的一个点,算法执行结束后 d [ t x ] [ t y ] d[t_x][t_y] d[tx][ty] 就是海洋区域中的点到 t t t 的最短距离,但是我们却不知道哪些 t t t 是海洋区域点的「最近陆地区域」,我们也不知道每个 s s s 距离它的「最近陆地区域」的曼哈顿距离。

考虑我们把陆地区域作为源点集、海洋区域作为目标点集,目标点集中的点 t t t 对应的 d [ t x ] [ t y ] d[t_x][t_y] d[tx][ty] 就是海洋区域 t t t 对应的距离它的「最近陆地区域」的曼哈顿距离,正是我们需要的,所以应该把陆地区域作为源点集。最终只需要比出 d [ t x ] [ t y ] d[t_x][t_y] d[tx][ty] 的最大值即可。如果使用 Dijkstra 算法,那么在初始化 d 数组时,把每个元素预置为 INF,所以如果发现最终比出的最大值为 INF,那么就返回 − 1 -1 1

由于这里的边权为 1 1 1 ,不如直接使用多源 BFS,在这里每个点都只会被松弛一次

class Solution {
public:
    int maxDistance(vector<vector<int>>& grid) {
        int n = grid.size();
        queue<pair<int, int>> q;
        int MAX_VALUE = n + n;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 1) {
                    grid[i][j] = 0;
                    q.push({i, j});
                } else grid[i][j] = MAX_VALUE;
            }
        }
        int d[4][2] = {-1, 0, 1, 0, 0, -1, 0, 1};
        int ans = -1;
        while (!q.empty()) {
            auto [x, y] = q.front(); q.pop();
            for (int i = 0; i < 4; ++i) {
                int u = x + d[i][0], v = y + d[i][1];
                if (u >= 0 && u < n && v >= 0 && v < n && grid[x][y] + 1 < grid[u][v]) {
                    // 只有海洋单元格的值会被更新,且一次性更新为到最近陆地单元格的距离
                    grid[u][v] = grid[x][y] + 1;
                    ans = max(ans, grid[u][v]);
                    q.push({u, v});
                }
            }
        }
        return ans;
    }
};

复杂度分析:

  • 时间复杂度: O ( m n ) O(mn) O(mn)
  • 空间复杂度: O ( m n ) O(mn) O(mn) ,虽然我们是原地修改,但是使用队列时,如果都是 1 1 1 都是陆地,就全部要入队。

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

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

相关文章

C++头文件和std命名空间

C 是在C语言的基础上开发的&#xff0c;早期的 C 还不完善&#xff0c;不支持命名空间&#xff0c;没有自己的编译器&#xff0c;而是将 C 代码翻译成C代码&#xff0c;再通过C编译器完成编译。 这个时候的 C 仍然在使用C语言的库&#xff0c;stdio.h、stdlib.h、string.h 等头…

idea 左下角的Git(Version Control)中显示Local Changes窗口

打开Local Changes窗口来查看当前Git仓库的本地变更。 使用快捷键: - Windows: Alt9 - Mac: Cmd9 解决&#xff1a; &#xff08;1&#xff09;idea打开settings &#xff08;2&#xff09;点击Version Control窗口选项卡&#xff0c;选择Commit选项&#xff0c;对 Use.... in…

二叉搜索树-----红黑树

✅<1>主页&#xff1a;我的代码爱吃辣&#x1f4c3;<2>知识讲解&#xff1a;数据结构——红黑树☂️<3>开发环境&#xff1a;Visual Studio 2022&#x1f4ac;<4>前言&#xff1a;红黑树也是一颗二叉搜索树&#xff0c;其作为map&#xff0c;set的底层…

【分析绘图】R语言实现一些常见的绘图

微生信-在线绘图网站 线性图 library(ggplot2)x <- rnorm(100, 14, 5) # rnorm(n, mean 0, sd 1) y <- x rnorm(100, 0, 1) ggplot(data NULL, aes(x x, y y)) # 开始绘图geom_point(color "darkred") # 添加点annotate("text",x 13,…

23款奔驰GLE450轿跑升级原厂外观暗夜套件,战斗感满满的

升级的方案基本都是替换原来车身部位的镀铬件&#xff0c;可能会有人问&#xff1a;“难道直接用改色膜贴黑不好吗&#xff1f;”如果是贴膜的话&#xff0c;第一个是颜色没有那么纯正&#xff0c;这些镀铬件贴黑的技术难度先抛开不说&#xff0c;即使贴上去了&#xff0c;那过…

原生小案例:如何使用HTML5 Canvas构建画板应用程序

使用HTML5 Canvas构建绘图应用是在Web浏览器中创建交互式和动态绘图体验的绝佳方式。HTML5 Canvas元素提供了一个绘图表面&#xff0c;允许您操作像素并以编程方式创建各种形状和图形。本文将为您提供使用HTML5 Canvas创建绘图应用的概述和指导。此外&#xff0c;它还将通过解释…

【MYSQL8.0从入门到精通】

文章目录 MySQL 8.0一.MySQL的多表操作1.外键约束&#xff08;一对多&#xff09;2.外键约束&#xff08;多对多&#xff09; MySQL 8.0 一.MySQL的多表操作 1.外键约束&#xff08;一对多&#xff09; 方式1 在创建表的同时创建外键约束 -- 1.创建主表 create table if no…

性能优化——分库分表

1、什么是分库分表 1.1、分表 将同一个库中的一张表&#xff08;比如SPU表&#xff09;按某种方式&#xff08;垂直拆分、水平拆分&#xff09;拆分成SPU1、SPU2、SPU3、SPU4…等若干张表&#xff0c;如下图所示&#xff1a; 1.2、分库 在表数据不变的情况下&#xff0c;对…

【锐捷】OSPF 多区域配置

【实验名称】 配置 OSPF 多区域。 【实验目的】 配置 OSPF 多区域&#xff0c;理解 OSPF 层次型网络的特点。 【背景描述】 本实验拓扑图中有 3 台路由器&#xff0c;路由器在区域 0 和区域 1 中&#xff0c;路由器 B 在区域 0 和区域 30&#xff0c; 路由器 C 在区域 30。 【需…

SQL 数据库

安装配置 【1】 MySQL安装配置教程&#xff08;超级详细、保姆级&#xff09; 【2】 MySQLNavicat安装配置教程&#xff08;超级详细、保姆级&#xff09; 学习资料 【戴师兄】SQL入门免费教程 刷题链接&#xff1a;https://share.mubu.com/doc/4BHMMbbvIMb 学习笔记&#xf…

vue3 pdf、word等文件下载

效果&#xff1a; <div class"byLawBox"><div class"titleBox">规章制度公示</div><div class"contentBox"><TableList:loading"byLawloading"ref"byLawtablistRef":hasImport"false"…

时序预测 | MATLAB实现SO-CNN-LSTM蛇群算法优化卷积长短期记忆神经网络时间序列预测

时序预测 | MATLAB实现SO-CNN-LSTM蛇群算法优化卷积长短期记忆神经网络时间序列预测 目录 时序预测 | MATLAB实现SO-CNN-LSTM蛇群算法优化卷积长短期记忆神经网络时间序列预测预测效果基本介绍程序设计学习总结参考资料 预测效果 基本介绍 时序预测 | MATLAB实现SO-CNN-LSTM蛇群…

清洁能源使用的社会发展意义

应用清洁能源是转变经济增加途径的有效手段&#xff0c;能够在减少污染物、降低企业经营成本的同时&#xff0c;提高企业经济效益和社会经济效益。 应用清洁能源是保护环境的最佳方式和必然选择&#xff0c;改变末端治理的现状&#xff0c;采取以预防为主的环境保护与发展理…

波奇学C++:stl的list模拟实现

list是双向带头链表。所以迭代器end()相当于哨兵卫的头。 list不支持和[]重载&#xff0c;原因在于list空间不是连续的&#xff0c;和[]的代价比较大。 访问第n个节点&#xff0c;只能用for循环&#xff0c;来实现 list<int> l; l.push_back(0); l.push_back(1); l.pu…

queue ide is not exists in YARN

报错内容: 2023-08-17 17:30:31.342 [ERROR] [BaseTaskScheduler-Thread-7 ] o.a.l.o.s.a.AsyncExecTaskRunnerImpl (79) [run] - Failed to execute task astJob_1_codeExec_1 org.apache.linkis.orchestrator.ecm.exception.ECMPluginErrorException: errCode:…

LeetCode--HOT100题(37)

目录 题目描述&#xff1a;104. 二叉树的最大深度&#xff08;简单&#xff09;题目接口解题思路代码 PS: 题目描述&#xff1a;104. 二叉树的最大深度&#xff08;简单&#xff09; 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远…

【Go 基础篇】Go语言中的defer关键字:延迟执行与资源管理

介绍 在Go语言中&#xff0c;defer 是一种用于延迟执行函数调用的关键字。它提供了一种简洁而强大的方式&#xff0c;用于在函数返回之前执行一些必要的清理操作或者释放资源。defer 的灵活性和易用性使得它在Go语言中广泛应用于资源管理、错误处理和代码结构优化等方面。&…

Redis笔记——(狂神说)待续

Nosql概述 为什么要用NoSql&#xff1f; 1、单机mysql的年代&#xff1a;90年代&#xff0c;网站访问量小&#xff0c;很多使用静态网页html写的&#xff0c;服务器没压力。 当时瓶颈是&#xff1a;1)数据量太大一个机器放不下。2)数据的索引(BTree)&#xff0c;一个机器内存也…

rabbitmq的优先级队列

在我们系统中有一个 订单催付 的场景&#xff0c;我们的客户在天猫下的订单 , 淘宝会及时将订单推送给我们&#xff0c;如果在用户设定的时间内未付款那么就会给用户推送一条短信提醒&#xff0c;很简单的一个功能对吧&#xff0c;但是&#xff0c;tianmao商家对我们来说&#…

数据工厂调研及结果展示

数据工厂 一、背景 在开发自测、测试迭代测试、产品验收的过程中&#xff0c;都需要各种各样的前置数据&#xff0c;大致分为如下几类&#xff1a; 账号&#xff08;实名、权益等级、注册等&#xff09; 货源&#xff08;优货、急走、相似、一手、普通货源等&#xff09; …