[LeetCode] 1162、地图分析

题目描述

你现在手里有一份大小为 N x N 的『地图』(网格) grid,上面的每个『区域』(单元格)都用 01 标记好了。其中 0 代表海洋,1 代表陆地,你知道距离陆地区域最远的海洋区域是是哪一个吗?请返回该海洋区域到离它最近的陆地区域的距离。

我们这里说的距离是『曼哈顿距离』( Manhattan Distance):(x0, y0)(x1, y1) 这两个区域之间的距离是 |x0 - x1| + |y0 - y1|

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RF3feezC-1578297806714)(./imgs/20200106155932.jpg)]

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

解题思路

这种找距离的题目是典型的“广度优先搜索”题目。

思路:一看到最值,首先想到BFS。我们可以先找出所有的陆地,然后从陆地开始向外进行BFS式的扩散,然后每扩散一层就将计数器加一,不断“填海造陆”直到整个地图再也不存在海洋为止。这个时候的计数器就是最远的海洋距离陆地的距离。

参考代码

class Solution {
public:
    int maxDistance(vector<vector<int>>& grid) {
        int rows = grid.size();
        if(rows == 0)
            return 0;
        int cols = grid[0].size();

        int dx[] = {0, 0, 1, -1};
        int dy[] = {1, -1, 0, 0};

        queue<int> q;
        for(int i = 0; i < rows; i++){
            for(int j = 0; j < cols; j++){
                if(grid[i][j] == 1)
                    q.push(i*cols + j);  // 很好用的小技巧(这里往queue里装 pair<int, int> 也行)
            }
        }

        if(q.size() == 0 || q.size() == rows * cols)
            return -1;

        int res = 0;
        bool flag = false;  // 设置这里flag的目的是防止计数多一个
        while(!q.empty()){
            int sizeOfq = q.size();
            while(sizeOfq--){  // 这个while会保证遍历“一整圈”(自己理解)
                int tmp = q.front();
                q.pop();
                int row = tmp / cols;   // 小技巧,恢复坐标
                int col = tmp % cols;

                for(int i = 0; i < 4; i++){
                    int new_row = row + dx[i];
                    int new_col = col + dy[i];
                    if(new_row >= 0 && new_row < rows && new_col >= 0 && new_col < cols && grid[new_row][new_col] == 0){
                        grid[new_row][new_col] = 1;  // bfs,必须在添加进queue的时候就进行着色,否则可能有重复遍历的问题!!(用 visited[] 数组时同理)
                        q.push(new_row * cols + new_col);  // 依旧用“i,j坐标封装”的小技巧
                        flag = true;
                    }
                }
            }

            if(flag){
                res++;
                flag = false;
            }
        }

        return res;
    }

};

更优雅一点的解法(推荐!

class Solution {
public:
    int maxDistance(vector<vector<int>>& grid) {
        int rows = grid.size();
        if(rows == 0)
            return 0;
        int cols = grid[0].size();

        int dx[] = {0, 0, 1, -1};
        int dy[] = {1, -1, 0, 0};

        queue<int> q;
        for(int i = 0; i < rows; i++){
            for(int j = 0; j < cols; j++){
                if(grid[i][j] == 1)
                    q.push(i*cols + j);  // 很好用的小技巧(这里往queue里装 pair<int, int> 也行)
            }
        }

        if(q.size() == 0 || q.size() == rows * cols)
            return -1;

        int res = 0;
        while(!q.empty()){
            int sizeOfq = q.size();
            while(sizeOfq--){  // 这个while会保证遍历“一整圈”(自己理解)
                int tmp = q.front();
                q.pop();
                int row = tmp / cols;   // 小技巧,恢复坐标
                int col = tmp % cols;

                for(int i = 0; i < 4; i++){
                    int new_row = row + dx[i];
                    int new_col = col + dy[i];
                    if(new_row >= 0 && new_row < rows && new_col >= 0 && new_col < cols && grid[new_row][new_col] == 0){
                        grid[new_row][new_col] = 1;  // bfs,必须在添加进queue的时候就进行着色,否则可能有重复遍历的问题!!(用 visited[] 数组时同理)
                        q.push(new_row * cols + new_col);  // 依旧用“i,j坐标封装”的小技巧
                    }
                }
            }
            
            if(!q.empty())  // 这个if的目的是:防止计数多一个
                res++;
        }

        return res;
    }

};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值