Shortest Distance from All Buildings
Description
You want to build a house on an empty land which reaches all buildings in the shortest amount of distance. You can only move up, down, left and right. You are given a 2D grid of values 0, 1 or 2, where:
Each 0 marks an empty land which you can pass by freely. Each 1 marks a building which you cannot pass through. Each 2 marks an obstacle which you cannot pass through. For example, given three buildings at (0,0), (0,4), (2,2), and an obstacle at (0,2):
1 - 0 - 2 - 0 - 1 | | | | | 0 - 0 - 0 - 0 - 0 | | | | | 0 - 0 - 1 - 0 - 0 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.
Hint
Train of Thought
Short version: BFS from every building, calculate the distances and find the minimum distance in the end.
Key optimization : we do not go into a land, if it is not accessible by at least one of previous buildings.
I don't use a fresh "visited" for each BFS. Instead, I walk only onto the cells that were reachable from all previous buildings. From the first building I only walk onto cells where grid is 0, and make them -1. From the second building I only walk onto cells where grid is -1, and I make them -2. And so on.
For a long explanation see here in my blog.
It runs in 13 ms.
It is the same idea as stefan's c++ solution. I didn't see it until now. I did this myself.
Also one may want to make a copy of grid if it is not suppose to be modified.
Code
int[] dx = {1, 0, -1, 0}, dy = {0, 1, 0, -1};
public int shortestDistance(int[][] grid) {
int m = grid.length, n = grid[0].length;
int[][] dist = new int[m][n];
// Initialize building list and accessibility matrix `grid`
List<Tuple> buildings = new ArrayList<>();
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j) {
if (grid[i][j] == 1)
buildings.add(new Tuple(i, j, 0));
grid[i][j] = -grid[i][j];
}
// BFS from every building, the kth building can only walks on grid[i][j] == k
for (int k = 0; k < buildings.size(); ++k)
bfs(buildings.get(k), k, dist, grid, m, n);
// Find the minimum distance
int ans = -1;
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
if (grid[i][j] == buildings.size() && (ans < 0 || dist[i][j] < ans))
ans = dist[i][j];
return ans;
}
public void bfs(Tuple root, int k, int[][] dist, int[][] grid, int m, int n) {
Queue<Tuple> q = new ArrayDeque<>();
q.add(root);
while (!q.isEmpty()) {
Tuple b = q.poll();
dist[b.y][b.x] += b.dist;
for (int i = 0; i < 4; ++i) {
int x = b.x + dx[i], y = b.y + dy[i];
if (y >= 0 && x >= 0 && y < m && x < n && grid[y][x] == k) {
grid[y][x] = k + 1;
q.add(new Tuple(y, x, b.dist + 1));
}
}
}
}
class Tuple {
public int y;
public int x;
public int dist;
public Tuple(int y, int x, int dist) {
this.y = y;
this.x = x;
this.dist = dist;
}
}