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 原题链接和其他优选题解。

相关文章
|
5月前
|
存储 数据可视化 Cloud Native
用Ganos低代码实现免切片遥感影像浏览(二):动态栅格瓦片
本文介绍了Ganos全新发布了动态栅格瓦片能力,帮助用户将库内栅格数据或栅格分析结果快速可视化,无需依赖类似GeoServer等空间服务中间件,技术栈短平快,使用灵活高效。
|
12月前
|
存储 编解码 定位技术
案例!从天地图中提取全市的建筑物矢量轮廓-以苏州市为例
案例!从天地图中提取全市的建筑物矢量轮廓-以苏州市为例
206 1
|
人工智能 数据挖掘 定位技术
GIS空间分析 栅格数据分析3 可达性分析
掌握栅格数据的可达性分析方法
349 0
|
数据挖掘 定位技术
GIS空间分析 栅格数据分析2 成本距离分析
掌握成本距离制图函数和成本方向函数的使用。
163 0
|
传感器 算法 前端开发
【应用SLAM技术建立二维栅格化地图】
【应用SLAM技术建立二维栅格化地图】
422 0
|
存储 人工智能 缓存
图是什么?地图?网络图?还是……
图是什么?地图?网络图?还是……
942 0
图是什么?地图?网络图?还是……
|
传感器 算法 前端开发
移动机器人 | 同时定位与建图
移动机器人 | 同时定位与建图
341 0
移动机器人 | 同时定位与建图
|
存储 算法 定位技术
四叉树应用于地图(点聚合)、碰撞检测等问题
四叉树应用于地图(点聚合)、碰撞检测等问题
1590 0
四叉树应用于地图(点聚合)、碰撞检测等问题
|
算法
多源BFS
复习acwing算法提高课的内容,本篇为讲解算法:多源BFS,关于时间复杂度:目前博主不太会计算,先鸽了,日后一定补上。
130 0
多源BFS
|
定位技术
使用ORBSLAM2进行kineticV2稠密建图,实时转octomap建图以及导航(下)
使用ORBSLAM2进行kineticV2稠密建图,实时转octomap建图以及导航(下)
1885 0
使用ORBSLAM2进行kineticV2稠密建图,实时转octomap建图以及导航(下)