Welcome to Subscribe On Youtube
Question
Formatted question description: https://leetcode.ca/all/317.html
You are given an m x n
grid grid
of values 0
, 1
, or 2
, where:
- each
0
marks an empty land that you can pass by freely, - each
1
marks a building that you cannot pass through, and - each
2
marks an obstacle that you cannot pass through.
You want to build a house on an empty land that reaches all buildings in the shortest total travel distance. You can only move up, down, left, and right.
Return the shortest travel distance for such a house. If it is not possible to build such a house according to the above rules, return -1
.
The total travel distance is the sum of the distances between the houses of the friends and the meeting point.
The distance is calculated using Manhattan Distance, where distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|
.
Example 1:
Input: grid = [[1,0,2,0,1],[0,0,0,0,0],[0,0,1,0,0]] Output: 7 Explanation: Given three buildings at (0,0), (0,4), (2,2), and an obstacle at (0,2). The point (1,2) is an ideal empty land to build a house, as the total travel distance of 3+3+1=7 is minimal. So return 7.
Example 2:
Input: grid = [[1,0]] Output: 1
Example 3:
Input: grid = [[1]] Output: -1
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 50
grid[i][j]
is either0
,1
, or2
.- There will be at least one building in the
grid
.
Algorithm
In some cases, the obstacle completely blocks a certain building, then -1
should be returned. So this problem can only be solved by traversing the maze
.
Need to use queue
to traverse, we perform a BFS traversal
of the whole picture for each building position, and establish a distance field of dist each time.
Since our BFS traversal
needs to mark the locations that should be visited, and we don’t want to build a two-dimensional matrix of visits, then, what should we do, here is a small trick,
- When we first traverse, we always find the position of
0
. After the traversal, we assign it to-1
. - In this way, in the next round of traversal, we will find the position of
-1
and assign them all to-2
, - And so on until all buildings are traversed
Then update the values of dist and sum during the traversal process. Note that our dist
is a local variable, and it is initialized to grid every time. The real distance field is accumulated in sum
. Since the position of the building is 1 in the grid, dist
initialization in the middle is also 1, and it needs to be subtracted by 1 when added to the sum
.
We use the value in the sum
to update the value of the result res, and finally see if we want to return -1 according to the value of result.
Code
-
import java.util.LinkedList; import java.util.Queue; public class Shortest_Distance_from_All_Buildings { public static void main(String[] args) { Shortest_Distance_from_All_Buildings out = new Shortest_Distance_from_All_Buildings(); Solution s = out.new Solution(); System.out.println(s.shortestDistance(new int[][] { {1,0,2,0,1},{0,0,0,0,0},{0,0,1,0,0} } )); } public class Solution { /** * @param grid: the 2D grid * @return: the shortest distance */ public int shortestDistance(int[][] grid) { if (grid == null || grid.length == 0 || grid[0].length == 0) { return 0; } int m = grid.length, n = grid[0].length; int[][] totalDistance = new int[m][n]; int step = 0; int res = 0; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == 1) { res = bfs(grid, i, j, step, totalDistance); step--; } } } return res == Integer.MAX_VALUE ? -1 : res; } private int bfs(int[][] grid, int x, int y, int step, int[][] totalDistance) { int res = Integer.MAX_VALUE; int m = grid.length; int n = grid[0].length;; Queue<Integer> queue = new LinkedList<>(); queue.offer(x * n + y); int curDistance = 0; int[] directions = {-1, 0, 1, 0, -1}; while (!queue.isEmpty()) { int l = queue.size(); curDistance++; while (l-- != 0) { int t = queue.poll(); x = t / n; // restore. could also be a tuple(x,y) put in queue y = t % n; for (int i = 0; i < 4; ++i) { int _x = x + directions[i], _y = y + directions[i + 1]; if (_x >= 0 && _x < m && _y >= 0 && _y < n && grid[_x][_y] == step) { queue.offer(_x * n + _y); totalDistance[_x][_y] += curDistance; grid[_x][_y]--; res = Math.min(res, totalDistance[_x][_y]); } } } } return res; } } } ############ class Solution { public int shortestDistance(int[][] grid) { int m = grid.length; int n = grid[0].length; Deque<int[]> q = new LinkedList<>(); int total = 0; int[][] cnt = new int[m][n]; int[][] dist = new int[m][n]; int[] dirs = {-1, 0, 1, 0, -1}; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == 1) { ++total; q.offer(new int[] {i, j}); int d = 0; boolean[][] vis = new boolean[m][n]; while (!q.isEmpty()) { ++d; for (int k = q.size(); k > 0; --k) { int[] p = q.poll(); for (int l = 0; l < 4; ++l) { int x = p[0] + dirs[l]; int y = p[1] + dirs[l + 1]; if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 0 && !vis[x][y]) { ++cnt[x][y]; dist[x][y] += d; q.offer(new int[] {x, y}); vis[x][y] = true; } } } } } } } int ans = Integer.MAX_VALUE; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == 0 && cnt[i][j] == total) { ans = Math.min(ans, dist[i][j]); } } } return ans == Integer.MAX_VALUE ? -1 : ans; } }
-
class Solution { public: int shortestDistance(vector<vector<int>>& grid) { int res = INT_MAX, buildingCnt = 0, m = grid.size(), n = grid[0].size(); vector<vector<int>> dist(m, vector<int>(n, 0)), cnt = dist; vector<vector<int>> dirs{ {0,-1},{-1,0},{0,1},{1,0} }; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == 1) { ++buildingCnt; queue<pair<int, int>> q; q.push({i, j}); vector<vector<bool>> visited(m, vector<bool>(n, false)); int level = 1; while (!q.empty()) { int size = q.size(); for (int s = 0; s < size; ++s) { int a = q.front().first, b = q.front().second; q.pop(); for (int k = 0; k < dirs.size(); ++k) { int x = a + dirs[k][0], y = b + dirs[k][1]; if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 0 && !visited[x][y]) { dist[x][y] += level; ++cnt[x][y]; visited[x][y] = true; q.push({x, y}); } } } ++level; } } } } for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == 0 && cnt[i][j] == buildingCnt) { res = min(res, dist[i][j]); } } } return res == INT_MAX ? -1 : res; } };
-
class Solution: def shortestDistance(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) q = deque() total = 0 # total building count # cnt: how many buildings can reach (x,y) # if there is a column all blockers, then (x,y) cannot reach every building cnt = [[0] * n for _ in range(m)] dist = [[0] * n for _ in range(m)] for i in range(m): for j in range(n): if grid[i][j] == 1: total += 1 q.append((i, j)) d = 0 vis = set() # reset for every free-land while q: d += 1 for _ in range(len(q)): r, c = q.popleft() for a, b in [[0, 1], [0, -1], [1, 0], [-1, 0]]: x, y = r + a, c + b if ( 0 <= x < m and 0 <= y < n and grid[x][y] == 0 and (x, y) not in vis ): cnt[x][y] += 1 dist[x][y] += d q.append((x, y)) vis.add((x, y)) ans = inf for i in range(m): for j in range(n): if grid[i][j] == 0 and cnt[i][j] == total: ans = min(ans, dist[i][j]) return -1 if ans == inf else ans ############ from collections import deque class Solution(object): def shortestDistance(self, grid): """ :type grid: List[List[int]] :rtype: int """ def bfs(si, sj, grid, buildNum, hit): dirs = [(-1, 0), (1, 0), (0, -1), (0, 1)] queue = deque([(si, sj, 0)]) visited = set([(si, sj)]) count = 1 while queue: i, j, dist = queue.popleft() for di, dj in dirs: newi, newj = i + di, j + dj if (newi, newj) in visited: continue if 0 <= newi < len(grid) and 0 <= newj < len(grid[0]) and grid[newi][newj] != 2: if grid[newi][newj] != 1: grid[newi][newj] -= dist + 1 hit[newi][newj] += 1 visited |= {(newi, newj)} queue.append((newi, newj, dist + 1)) else: count += 1 visited |= {(newi, newj)} if count != buildNum: print count, buildNum return False return True count = 0 for i in range(0, len(grid)): for j in range(0, len(grid[0])): if grid[i][j] == 1: count += 1 hit = [[0] * len(grid[0]) for _ in range(0, len(grid))] for i in range(0, len(grid)): for j in range(0, len(grid[0])): if grid[i][j] == 1: if not bfs(i, j, grid, count, hit): return -1 ans = float("-inf") for i in range(0, len(grid)): for j in range(0, len(grid[0])): if grid[i][j] < 0 and hit[i][j] == count: ans = max(ans, grid[i][j]) grid[i][j] = 0 return -ans if ans != float("-inf") else -1
-
func shortestDistance(grid [][]int) int { m, n := len(grid), len(grid[0]) var q [][]int total := 0 cnt := make([][]int, m) dist := make([][]int, m) for i := range cnt { cnt[i] = make([]int, n) dist[i] = make([]int, n) } dirs := []int{-1, 0, 1, 0, -1} for i := 0; i < m; i++ { for j := 0; j < n; j++ { if grid[i][j] == 1 { total++ q = append(q, []int{i, j}) vis := make([]bool, m*n) d := 0 for len(q) > 0 { d++ for k := len(q); k > 0; k-- { p := q[0] q = q[1:] for l := 0; l < 4; l++ { x, y := p[0]+dirs[l], p[1]+dirs[l+1] if x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 0 && !vis[x*n+y] { cnt[x][y]++ dist[x][y] += d q = append(q, []int{x, y}) vis[x*n+y] = true } } } } } } } ans := math.MaxInt32 for i := 0; i < m; i++ { for j := 0; j < n; j++ { if grid[i][j] == 0 && cnt[i][j] == total { if ans > dist[i][j] { ans = dist[i][j] } } } } if ans == math.MaxInt32 { return -1 } return ans }