之前听朋友说LeetCode出了一道新题,但是一直在TLE,我就找时间做了一下。这题是一个比较典型的BFS的题目,自己匆忙写了一个答案,没有考虑优化的问题,应该是有更好的解法的。
原题如下:
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.
Note:
There will be at least one building. If it is not possible to build such house according to the above rules, return -1.
基本想法就是从每个数值为1的点做bfs,遇到为0的点就加上相应的距离。这题因为要求到所有1的距离和最小的点,所以就可以无脑iterate over所有数值为1的点,并开一个二维数组来记录各个点的累加距离值。最后要检查一下所有结果中的值,确保其可以reach到所有的值为1的点,若不存在这样的,则返回-1。代码如下,比较冗长,等有机会再优化一下吧。
1 public class Solution { 2 public int shortestDistance(int[][] grid) { 3 int result = Integer.MAX_VALUE; 4 boolean[][] done = new boolean[grid.length][grid[0].length]; 5 int[][] cost = new int[grid.length][grid[0].length]; 6 int[][] count = new int[grid.length][grid[0].length]; 7 int total = 0; // total # of 1 8 for (int i = 0; i < grid.length; i++) { 9 for (int j = 0; j < grid[0].length; j++) { 10 done[i][j] = grid[i][j] != 0; 11 total = grid[i][j] == 1 ? total + 1 : total; 12 } 13 } 14 for (int i = 0; i < grid.length; i++) { 15 for (int j = 0; j < grid[0].length; j++) { 16 if (grid[i][j] == 1) { 17 Deque<Integer> row = new ArrayDeque<>(); 18 Deque<Integer> col = new ArrayDeque<>(); 19 enqueue(row, col, i, j, done, grid); 20 bfs(row, col, grid, cost, done, count, 1); 21 } 22 } 23 } 24 if (!isValid(count, total)) { 25 return -1; 26 } 27 for (int i = 0; i < cost.length; i++) { 28 for (int j = 0; j < cost[0].length; j++) { 29 if (count[i][j] == total) { 30 result = cost[i][j] > 0 ? Math.min(result, cost[i][j]) : result; 31 } 32 } 33 } 34 return result; 35 } 36 37 private void bfs(Deque<Integer> row, Deque<Integer> col, int[][] grid, int[][] cost, boolean[][] done, int[][] count, int distance) { 38 if (row.isEmpty()) { 39 return; 40 } 41 int size = row.size(); 42 List<Integer> row1 = new ArrayList<>(); 43 List<Integer> col1 = new ArrayList<>(); 44 for (int k = 0; k < size; k++) { 45 int i = row.poll(); 46 int j = col.poll(); 47 row1.add(i); 48 col1.add(j); 49 cost[i][j] += distance; 50 count[i][j] += 1; 51 enqueue(row, col, i, j, done, grid); 52 } 53 bfs(row, col, grid, cost, done, count, distance + 1); 54 for (int i = 0; i < row1.size(); i++) { 55 done[row1.get(i)][col1.get(i)] = false; 56 } 57 } 58 59 private void enqueue(Deque<Integer> row, Deque<Integer> col, int i, int j, boolean[][] done, int[][] grid) { 60 int down = i + 1; 61 int up = i - 1; 62 int left = j - 1; 63 int right = j + 1; 64 if (up >= 0 && !done[up][j] && grid[up][j] == 0) { 65 row.offer(up); 66 col.offer(j); 67 done[up][j] = true; 68 } 69 if (down < grid.length && !done[down][j] && grid[down][j] == 0) { 70 row.offer(down); 71 col.offer(j); 72 done[down][j] = true; 73 } 74 if (left >= 0 && !done[i][left] && grid[i][left] == 0) { 75 row.offer(i); 76 col.offer(left); 77 done[i][left] = true; 78 } 79 if (right < grid[0].length && !done[i][right] && grid[i][right] == 0) { 80 row.offer(i); 81 col.offer(right); 82 done[i][right] = true; 83 } 84 } 85 86 private boolean isValid(int[][] count, int total) { 87 for (int[] aCount : count) { 88 for (int c : aCount) { 89 if (c == total) { 90 return true; 91 } 92 } 93 } 94 return false; 95 } 96 }