Skip to content

Latest commit

 

History

History

2812

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

You are given a 0-indexed 2D matrix grid of size n x n, where (r, c) represents:

  • A cell containing a thief if grid[r][c] = 1
  • An empty cell if grid[r][c] = 0

You are initially positioned at cell (0, 0). In one move, you can move to any adjacent cell in the grid, including cells containing thieves.

The safeness factor of a path on the grid is defined as the minimum manhattan distance from any cell in the path to any thief in the grid.

Return the maximum safeness factor of all paths leading to cell (n - 1, n - 1).

An adjacent cell of cell (r, c), is one of the cells (r, c + 1), (r, c - 1), (r + 1, c) and (r - 1, c) if it exists.

The Manhattan distance between two cells (a, b) and (x, y) is equal to |a - x| + |b - y|, where |val| denotes the absolute value of val.

 

Example 1:

Input: grid = [[1,0,0],[0,0,0],[0,0,1]]
Output: 0
Explanation: All paths from (0, 0) to (n - 1, n - 1) go through the thieves in cells (0, 0) and (n - 1, n - 1).

Example 2:

Input: grid = [[0,0,1],[0,0,0],[0,0,0]]
Output: 2
Explanation: The path depicted in the picture above has a safeness factor of 2 since:
- The closest cell of the path to the thief at cell (0, 2) is cell (0, 0). The distance between them is | 0 - 0 | + | 0 - 2 | = 2.
It can be shown that there are no other paths with a higher safeness factor.

Example 3:

Input: grid = [[0,0,0,1],[0,0,0,0],[0,0,0,0],[1,0,0,0]]
Output: 2
Explanation: The path depicted in the picture above has a safeness factor of 2 since:
- The closest cell of the path to the thief at cell (0, 3) is cell (1, 2). The distance between them is | 0 - 1 | + | 3 - 2 | = 2.
- The closest cell of the path to the thief at cell (3, 0) is cell (3, 2). The distance between them is | 3 - 3 | + | 0 - 2 | = 2.
It can be shown that there are no other paths with a higher safeness factor.

 

Constraints:

  • 1 <= grid.length == n <= 400
  • grid[i].length == n
  • grid[i][j] is either 0 or 1.
  • There is at least one thief in the grid.

Companies: IMC, Google

Related Topics:
Array, Binary Search, Breadth-First Search, Union Find, Matrix

Similar Questions:

Hints:

  • Consider using both BFS and binary search together.
  • Launch a BFS starting from all the cells containing thieves to calculate d[x][y] which is the smallest Manhattan distance from (x, y) to the nearest grid that contains thieves.
  • To check if the bottom-right cell of the grid can be reached through a path of safeness factor v, eliminate all cells (x, y) such that grid[x][y] < v. if (0, 0) and (n - 1, n - 1) are still connected, there exists a path between (0, 0) and (n - 1, n - 1) of safeness factor v.
  • Binary search over the final safeness factor v.

Solution 1.

  1. BFS to calculate the distance to thieves for each node.
  2. Dijkstra to calculate the maximum safeness factor.
// OJ: https://leetcode.com/problems/find-the-safest-path-in-a-grid
// Author: github.com/lzl124631x
// Time: O(MNlog(MN))
// Space: O(MN)
class Solution {
public:
    int maximumSafenessFactor(vector<vector<int>>& A) {
        int N = A.size(), dirs[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
        vector<vector<int>> dist(N, vector<int>(N, INT_MAX)), factor(N, vector<int>(N, -1));
        queue<pair<int, int>> q;
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < N; ++j) {
                if (A[i][j] == 0) continue;
                q.emplace(i, j);
                dist[i][j] = 0;
            }
        }
        while (q.size()) {
            int cnt = q.size();
            while (cnt--) {
                auto [x, y] = q.front();
                q.pop();
                for (auto &[dx, dy] : dirs) {
                    int a = x + dx, b = y + dy;
                    if (a < 0 || a >= N || b < 0 || b >= N || dist[a][b] != INT_MAX) continue;
                    dist[a][b] = 1 + dist[x][y];
                    q.emplace(a, b);
                }
            }
        }
        typedef array<int, 3> Node; // factor, x, y
        priority_queue<Node> pq;
        factor[0][0] = dist[0][0];
        pq.push({factor[0][0], 0, 0});
        while (pq.size()) {
            auto [f, x, y] = pq.top();
            if (x == N - 1 && y == N - 1) return f;
            pq.pop();
            for (auto &[dx, dy] : dirs) {
                int a = x + dx, b = y + dy;
                if (a < 0 || a >= N || b < 0 || b >= N || factor[a][b] != -1) continue;
                factor[a][b] = min(dist[a][b], factor[x][y]);
                pq.push({factor[a][b], a, b});
            }
        }
        return -1;
    }
};

Solution 2.

  1. BFS to calculate the distance to thieves for each node.
  2. Binary Search limit within [0, maximumDistance] to see if there exists a path each cell of which has a distance >= limit. The maximum limit is the answer.
// OJ: https://leetcode.com/problems/find-the-safest-path-in-a-grid
// Author: github.com/lzl124631x
// Time: O(MNlog(M + N))
// Space: O(MN)
class Solution {
public:
    int maximumSafenessFactor(vector<vector<int>>& A) {
        int N = A.size(), dirs[4][2] = {{0,1},{0,-1},{1,0},{-1,0}}, maxDist = 0;
        vector<vector<int>> dist(N, vector<int>(N, INT_MAX));
        queue<pair<int, int>> q;
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < N; ++j) {
                if (A[i][j] == 0) continue;
                q.emplace(i, j);
                dist[i][j] = 0;
            }
        }
        while (q.size()) {
            int cnt = q.size();
            while (cnt--) {
                auto [x, y] = q.front();
                q.pop();
                for (auto &[dx, dy] : dirs) {
                    int a = x + dx, b = y + dy;
                    if (a < 0 || a >= N || b < 0 || b >= N || dist[a][b] != INT_MAX) continue;
                    dist[a][b] = 1 + dist[x][y];
                    maxDist = max(maxDist, dist[a][b]);
                    q.emplace(a, b);
                }
            }
        }
        int L = 0, R = maxDist;
        vector<vector<bool>> seen;
        auto valid = [&](int limit) { // returns true if there exists a path each cell of which has a distance `>= limit`.
            seen.assign(N, vector<bool>(N));
            function<bool(int, int)> dfs = [&](int x, int y) -> bool {
                if (seen[x][y]) return false;
                seen[x][y] = true;
                if (dist[x][y] < limit) return false;
                if (x == N - 1 && y == N - 1) return true;
                for (auto &[dx, dy] : dirs) {
                    int a = x + dx, b = y + dy;
                    if (a < 0 || a >= N || b < 0 || b >= N) continue;
                    if (dfs(a, b)) return true;
                }
                return false;
            };
            return dfs(0, 0);
        };
        while (L <= R) {
            int M = (L + R) / 2;
            if (valid(M)) L = M + 1;
            else R = M - 1;
        }
        return R;
    }
};