[LeetCode] 1162. As Far from Land as Possible 地圖分析



Given an n x n grid containing only values 0 and 1, where 0 represents water and 1 represents land, find a water cell such that its distance to the nearest land cell is maximized, and return the distance. If no land or water exists in the grid, return -1.

The distance used in this problem is the Manhattan distance: the distance between two cells (x0, y0) and (x1, y1) is |x0 - x1| + |y0 - y1|.

Example 1:

Input: grid = [[1,0,1],[0,0,0],[1,0,1]]
Output: 2
Explanation: The cell (1, 1) is as far as possible from all the land with distance 2.

Example 2:

Input: grid = [[1,0,0],[0,0,0],[0,0,0]]
Output: 4
Explanation: The cell (2, 2) is as far as possible from all the land with distance 4.

Constraints:

  • n == grid.length
  • n == grid[i].length
  • 1 <= n <= 100
  • grid[i][j] is 0 or 1

這道題給了一個只有0和1的二維數組,說是0表示水,1表示陸地,現在讓找出一個0的位置,使得其離最近的1的距離最大,這里的距離用曼哈頓距離表示。這里最暴力的方法就是遍歷每個0的位置,對於每個遍歷到的0,再遍歷每個1的位置,計算它們的距離,找到最小的距離保存為該0位置的距離,然后在所有0位置的距離中找出最大的。這種方法不是很高效,目測無法通過 OJ,博主都沒有嘗試。其實這道題的比較好的解法是建立距離場,即每個大於1的數字表示該位置到任意一個1位置的最短距離,在之前那道 Shortest Distance from All Buildings 就用過這種方法。建立距離場用 BFS 比較方便,因為其是一層一層往外擴散的遍歷,這里需要注意的是要一次把所有1的位置都加入 queue 中一起遍歷,而不是對每個1都進行 BFS,否則還是過不了 OJ。這里先把位置1都加入 queue,然后這里先做個剪枝,若位置1的個數為0,或者為 n^2,表示沒有陸地,或者沒有水,直接返回 -1。否則進行 while 循環,步數 step 加1,然后用 for 循環確保進行層序遍歷,一定要將 q.size() 放到初始化中,因為其值可能改變。然后就是標准的 BFS 寫法了,取隊首元素,遍歷其相鄰四個結點,若沒有越界且值為0,則將當前位置值更新為 step,然后將這個位置加入 queue 中繼續遍歷。循環退出后返回 step-1 即可,參見代碼如下:


解法一:

class Solution {
public:
    int maxDistance(vector<vector<int>>& grid) {
        int step = 0, n = grid.size();
        vector<vector<int>> dirs{{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
        queue<vector<int>> q;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 0) continue;
                q.push(vector<int>{i, j});
            }
        }
        if (q.size() == 0 || q.size() == n * n) return -1;
        while (!q.empty()) {
            ++step;
            for (int k = q.size(); k > 0; --k) {
                auto t = q.front(); q.pop();
                for (auto dir : dirs) {
                    int x = t[0] + dir[0], y = t[1] + dir[1];
                    if (x < 0 || x >= n || y < 0 || y >= n || grid[x][y] != 0) continue;
                    grid[x][y] = step;
                    q.push({x, y});
                }
            }
        }
        return step - 1;
    }
};

我們也可以強行用 DFS 來做,這里對於每一個值為1的點都調用遞歸函數,更新跟其相連的所有0位置的距離,最終也能算出整個距離場,從而查找出最大的距離,參見代碼如下:


解法二:

class Solution {
public:
    int maxDistance(vector<vector<int>>& grid) {
        int res = -1, n = grid.size();
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 1) {
                    grid[i][j] = 0;
                    helper(grid, i, j);
                }
            }
        }
        for (int i = n - 1; i >= 0; --i) {
            for (int j = n - 1; j >= 0; --j) {
                if (grid[i][j] > 1) res = max(res, grid[i][j] - 1);
            }
        }
        return res;
    }
    void helper(vector<vector<int>>& grid, int i, int j, int dist = 1) {
        int n = grid.size();
        if (i < 0 || j < 0 || i >= n || j >= n || (grid[i][j] != 0 && grid[i][j] <= dist)) return;
        grid[i][j] = dist;
        helper(grid, i - 1, j, dist + 1);
        helper(grid, i + 1, j, dist + 1);
        helper(grid, i, j - 1, dist + 1);
        helper(grid, i, j + 1, dist + 1);
    }
};

其實這道題的最優解法並不是 BFS 或者 DFS,而是下面這種兩次掃描的方法,在之前那道 01 Matrix 中就使用過。有點像動態規划的感覺,還是建立距離場,先從左上遍歷到右下,遇到1的位置跳過,然后初始化0位置的值為 201(因為n不超過 100,所以距離不會超過 200),然后用左邊和上邊的值加1來更新當前位置的,注意避免越界。然后從右邊再遍歷到左上,還是遇到1的位置跳過,然后用右邊和下邊的值加1來更新當前位置的,注意避免越界,同時還要更新結果 res 的值。最終若 res 為 201,則返回 -1,否則返回 res-1,參見代碼如下:


解法三:

class Solution {
public:
    int maxDistance(vector<vector<int>>& grid) {
        int res = 0, n = grid.size();
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 1) continue;
                grid[i][j] = 201;
                if (i > 0) grid[i][j] = min(grid[i][j], grid[i - 1][j] + 1);
                if (j > 0) grid[i][j] = min(grid[i][j], grid[i][j - 1] + 1);
            }
        }
        for (int i = n - 1; i >= 0; --i) {
            for (int j = n - 1; j >= 0; --j) {
                if (grid[i][j] == 1) continue;
                if (i < n - 1) grid[i][j] = min(grid[i][j], grid[i + 1][j] + 1);
                if (j < n - 1) grid[i][j] = min(grid[i][j], grid[i][j + 1] + 1);
                res = max(res, grid[i][j]);
            }
        }
        return res == 201 ? -1 : res - 1;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1162


類似題目:

Shortest Distance from All Buildings

01 Matrix


參考資料:

https://leetcode.com/problems/as-far-from-land-as-possible/

https://leetcode.com/problems/as-far-from-land-as-possible/discuss/360963/C%2B%2B-with-picture-DFS-and-BFS

https://leetcode.com/problems/as-far-from-land-as-possible/discuss/422691/7ms-DP-solution-with-example-beats-100


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM