1765. 地图中的最高点 : 多源 BFS 运用题

简介: 1765. 地图中的最高点 : 多源 BFS 运用题

网络异常,图片无法展示
|


题目描述



这是 LeetCode 上的 1765. 地图中的最高点 ,难度为 中等


Tag : 「图论搜索」、「多源 BFS」


给你一个大小为 m x n 的整数矩阵 isWater ,它代表了一个由 陆地 和 水域 单元格组成的地图。


  • 如果 isWater[i][j] == 0 ,格子 (i, j) 是一个 陆地 格子。
  • 如果 isWater[i][j] == 1 ,格子 (i, j) 是一个 水域 格子。


你需要按照如下规则给每个单元格安排高度:


  • 每个格子的高度都必须是非负的。
  • 如果一个格子是是 水域 ,那么它的高度必须为 00
  • 任意相邻的格子高度差 至多 为 1 。当两个格子在正东、南、西、北方向上相互紧挨着,就称它们为相邻的格子。(也就是说它们有一条公共边)


找到一种安排高度的方案,使得矩阵中的最高高度值 最大 。


请你返回一个大小为 m x n 的整数矩阵 height ,其中 height[i][j] 是格子 (i, j) 的高度。如果有多种解法,请返回 任意一个 。


示例 1:


网络异常,图片无法展示
|


输入:isWater = [[0,1],[0,0]]
输出:[[1,0],[2,1]]
解释:上图展示了给各个格子安排的高度。
蓝色格子是水域格,绿色格子是陆地格。
复制代码


示例 2:


网络异常,图片无法展示
|


输入:isWater = [[0,0,1],[1,0,0],[0,0,0]]
输出:[[1,1,0],[0,1,1],[1,2,2]]
解释:所有安排方案中,最高可行高度为 2 。
任意安排方案中,只要最高高度为 2 且符合上述规则的,都为可行方案。
复制代码


提示:


  • m == isWater.lengthm==isWater.length
  • n == isWater[i].lengthn==isWater[i].length
  • 1 <= m, n <= 10001<=m,n<=1000
  • isWater[i][j] 要么是 00 ,要么是 11
  • 至少有 11 个水域格子。


多源 BFS



这是一道「多源 BFS」板子题,对「多源 BFS」不熟悉的同学,可以看看前置 🧀:多源 BFS 入门


里面详解了「多源 BFS」与「单源 BFS」板子上的区别,强调了可以通过建立「虚拟源点」的方式,将「多源 BFS」转换回「单源 BFS」问题。


回到本题,题目规定了水域区域的高度为 00,然后相邻格子之间的高度差至多为 11

我们可以将所有水域(高度为 00)区域进行入队,然后跑一遍 BFS 即可。


将所有水域(高度为 00)区域进行入队的操作可看作是将与「虚拟源点」链接的节点进行入队(也等价于起始只将虚拟源点入队):


网络异常,图片无法展示
|


容易证明这样做法的正确性:对于一个「陆地」区域(高度可变)而言,其所能填入的高度,取决于其距离其他「水域」区域的距离,而我们最终要让整个答案矩阵合法,因此每个「陆地」区域应该取其所能填入的高度的「下界」,即只由「距离它最近的水域」区域所更新,这符合 BFS 的性质。


代码(感谢 @Benhao@5cm/s 🌸 同学提供的其他语言版本):


class Solution {
    public int[][] highestPeak(int[][] g) {
        int m = g.length, n = g[0].length;
        int[][] ans = new int[m][n];
        Deque<int[]> d = new ArrayDeque<>();
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (g[i][j] == 1) d.addLast(new int[]{i, j});
                ans[i][j] = g[i][j] == 1 ? 0 : -1;
            }
        }
        int[][] dirs = new int[][]{{1,0}, {-1,0}, {0,1}, {0,-1}};
        int h = 1;
        while (!d.isEmpty()) {
            int size = d.size();
            while (size-- > 0) {
                int[] info = d.pollFirst();
                int x = info[0], y = info[1];
                for (int[] di : dirs) {
                    int nx = x + di[0], ny = y + di[1];
                    if (nx < 0 || nx >= m || ny < 0 || ny >= n) continue;
                    if (ans[nx][ny] != -1) continue;
                    ans[nx][ny] = h;
                    d.addLast(new int[]{nx, ny});
                }
            }
            h++;
        }
        return ans;
    }
}
复制代码

class Solution:
    def highestPeak(self, isWater: List[List[int]]) -> List[List[int]]:
        m, n = len(isWater), len(isWater[0])
        ans = [[0] * n for _ in range(m)]
        d = deque()
        for i in range(m):
            for j in range(n):
                if isWater[i][j]:
                    d.append((i, j))
                ans[i][j] = 0 if isWater[i][j] else -1
        dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)]
        h = 1
        while d:
            size = len(d)
            for _ in range(size):
                x, y = d.popleft()
                for di in dirs:
                    nx, ny = x + di[0], y + di[1]
                    if 0 <= nx < m and 0 <= ny < n and ans[nx][ny] == -1:
                        ans[nx][ny] = h
                        d.append((nx, ny))
            h += 1
        return ans
复制代码

func highestPeak(isWater [][]int) [][]int {
    m, n := len(isWater), len(isWater[0])
    ans, d := make([][]int, m), [][]int{}
    for i := 0; i < m; i++ {
        ans[i] = make([]int, n)
        for j := 0; j < n; j++ {
            if isWater[i][j] == 1 {
                d = append(d, []int{i, j})
                ans[i][j] = 0
            } else {
                ans[i][j] = -1
            }
        }
    }
    dirs := [][]int{{1,0}, {-1,0}, {0,1}, {0,-1}}
    for h := 1; len(d) > 0; h++ {
        for size := len(d); size > 0; size--{
            info := d[0]
            d = d[1:]
            x, y := info[0], info[1]
            for _, di := range dirs {
                nx, ny := x + di[0], y + di[1]
                if nx >= 0 && nx < m && ny >= 0 && ny < n && ans[nx][ny] == -1 {
                    ans[nx][ny] = h
                    d = append(d, []int{nx, ny})
                }
            }
        }
    }
    return ans
}
复制代码

const int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
class Solution {
public:
    vector<vector<int>> highestPeak(vector<vector<int>>& g) {
        int n = g.size(), m = g[0].size();
        queue<pair<int, int>> q;
        vector<vector<int>> ans(n, vector<int>(m, 0));
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                if (g[i][j] == 1) {
                    q.emplace(i, j);
                } else {
                    ans[i][j] = -1;
                }
            }
        }
        while (!q.empty()) {
            auto [x, y] = q.front(); q.pop();
            for (int i = 0; i < 4; ++i) {
                int a = x + dx[i], b = y + dy[i];
                if (a < 0 || a == n || b < 0 || b == m) continue;
                if (ans[a][b] >= 0) continue;
                ans[a][b] = ans[x][y] + 1;
                q.emplace(a, b);
            }
        }
        return ans;
    }
};
复制代码


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


最后



这是我们「刷穿 LeetCode」系列文章的第 No.1765 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。


在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。


为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:github.com/SharingSour…


在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

相关文章
|
2月前
|
SQL 关系型数据库 分布式数据库
用Ganos低代码实现免切片遥感影像浏览
本文介绍了一种基于PolarDB兼容PostgreSQL 14的高效栅格数据管理和可视化方案。推荐配置包括4核CPU、16GB内存、50GB磁盘等。通过创建扩展并上传影像至OSS,利用SQL语句完成数据导入、镶嵌、匀色及金字塔构建。重点介绍了使用ST_AsTile函数动态生成标准瓦片的方法,支持多种格式和增强方式。前端通过Python实现服务接口,实现实时、高效的数据展示。此方案具有实时性强、存储成本低等优点,适合快速可视化大量栅格数据。
42 0
|
6月前
|
存储 数据可视化 Cloud Native
用Ganos低代码实现免切片遥感影像浏览(二):动态栅格瓦片
本文介绍了Ganos全新发布了动态栅格瓦片能力,帮助用户将库内栅格数据或栅格分析结果快速可视化,无需依赖类似GeoServer等空间服务中间件,技术栈短平快,使用灵活高效。
|
前端开发 关系型数据库 定位技术
用Ganos低代码实现免切片遥感影像浏览(一)
本文介绍了使用PolarDB-PG数据库配合Ganos时空数据库引擎,不借助第三方工具仅利用SQL语句快速管理与展示遥感影像数据的一种方法。Ganos共提供两种影像免切浏览的方法,一种使用窗口范围获取影像数据展示,另一种通过固定瓦片范围获取影像数据展示,本文详细介绍第一种方法并提供了前后端实操代码帮助用户可以快速理解Ganos Raster的使用细节。
|
人工智能 数据可视化 数据挖掘
这图怎么画| 富集分析之双向柱状图
这图怎么画| 富集分析之双向柱状图
187 0
ArcGIS提取路网节点
ArcGIS提取路网节点
177 0
|
存储 人工智能 缓存
图是什么?地图?网络图?还是……
图是什么?地图?网络图?还是……
950 0
图是什么?地图?网络图?还是……
|
存储 算法 定位技术
四叉树应用于地图(点聚合)、碰撞检测等问题
四叉树应用于地图(点聚合)、碰撞检测等问题
1650 0
四叉树应用于地图(点聚合)、碰撞检测等问题
|
算法
多源BFS
复习acwing算法提高课的内容,本篇为讲解算法:多源BFS,关于时间复杂度:目前博主不太会计算,先鸽了,日后一定补上。
133 0
多源BFS
|
定位技术
使用ORBSLAM2进行kineticV2稠密建图,实时转octomap建图以及导航(下)
使用ORBSLAM2进行kineticV2稠密建图,实时转octomap建图以及导航(下)
1982 0
使用ORBSLAM2进行kineticV2稠密建图,实时转octomap建图以及导航(下)