Shortest Distance from All Buildings
Question
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):
Solution
我想到的解法跟參考解答差不多,但我拿到 TLE。我的想法是,當 grid 值等於 1 的時候,去跑 bfs,然後照每棟 building 去新建一個 int[][] 存 bfs 結果。把這些 int[][] 都存在一個 list 裡,最後再根據 grid 值等於 0 時,去把這些表找出來並把該位置的各個 int[][] 值相加。
參考解答之後,其實不需要存在一個 list,只需要建立一個 int[][] distance,然後每次的結果根據上次的結果 += 起來就好。不過,這題麻煩就麻煩在,你是在 2D array 裡面做 BFS,會面臨到需要記錄該點有沒有在這次 iteration 被訪問過。可以用兩個方法來完成這件事:
- 建立一個 boolean[][] 來記錄
- 直接修改 grid 的值
解答用了第二種。絲路在於,我們有一個記錄目前總共有幾棟 building 的 num,先把 -num 傳進 bfs。由於一開始是 0,所以是 0 的點就可以在這次的 iteration 被訪問。被訪問到的點,在 grid 上面的值要減 1,用這個方式來記錄被訪問過。所以在下次 num = 1 時,傳進去會是 -1,那就可以只訪問上個 iteration 有被成功訪問到的點(題目要求最後的 house 必須建在每棟 building 都可以訪問到)
在 2D array 裡做 BFS,可以用 Queue〈int[]〉。網路上有些人選擇寫一個 Tuple class 來記錄
final int[][] steps = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int[][] distance;
public int shortestDistance(int[][] grid) {
if (grid == null || grid.length == 0) {
return 0;
}
distance = new int[grid.length][grid[0].length];
int num = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == 1) {
bfs(grid, i, j, -num);
num++;
}
}
}
int min = Integer.MAX_VALUE;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == -num) {
min = Math.min(distance[i][j], min);
}
}
}
return min == Integer.MAX_VALUE? -1 : min;
}
public void bfs(int[][] grid, int row, int col, int num) {
Queue<int[]> queue = new LinkedList<int[]>();
queue.offer(new int[]{row, col});
int level = 0;
while (!queue.isEmpty()) {
level++;
for (int i = queue.size(); i > 0; i--) {
int[] cur = queue.poll();
for (int[] step : steps) {
int x = step[0] + cur[0], y = step[1] + cur[1];
if (x >= 0 && x < grid.length && y >= 0 && y < grid[0].length && grid[x][y] == num) {
distance[x][y] += level;
queue.offer(new int[]{x, y});
grid[x][y]--;
}
}
}
}
}