Given a 2D grid, each cell is either a wall2, an house1or empty0(the number zero, one, two), find a place to build a post office so that the sum of the distance from the post office to all the houses is smallest.

Return the smallest sum of distance. Return-1if it is not possible.

Notice
  • You cannot pass through wall and house, but can pass through empty.
  • You only build post office on an empty.

Have you met this question in a real interview?

Yes

Example

Given a grid:

0 1 0 0 0
1 0 0 2 1
0 1 0 0 0

return8, You can build at(1,1). (Placing a post office at (1,1), the distance that post office to all the house sum is smallest.)

因为有了墙,所以重心不再一定是最优距离和。可以搜索(BFS)所有房子到每一个空地的距离,并且对于每一个空地,记录是否所有房子都到达过,并从中选取最小的距离和即可

public class Solution {
    /**
     * @param grid a 2D grid
     * @return an integer
     */
    class Pair {
        int n;
        int m;
        public Pair (int n, int m) {
            this.n = n;
            this.m = m;
        }
    }


    public int HOUSE = 1;
    public int EMPTY = 0;
    public int WALL = 2;

    public int[] deltaN = {1, -1, 0, 0};
    public int[] deltaM = {0, 0, -1, 1};

    public int shortestDistance(int[][] grid) {
        // Write your code here
        if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) {
            return -1;
        }

        //get the house list
        ArrayList<Pair> houseList = getHouseList(grid);


        //get the smallest count by bfs through all houses to all empty points
        return countMinDistance(grid, houseList);
    }

    public ArrayList<Pair> getHouseList(int[][] grid) {
        ArrayList<Pair> ans = new ArrayList<Pair>();

        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == HOUSE) {
                    ans.add(new Pair(i, j));
                }
            }
        }

        return ans;
    }

    public int countMinDistance(int[][] grid, ArrayList<Pair> houseList) {
        int[][] sumDistance = new int[grid.length][grid[0].length];
        int[][] visitCount = new int[grid.length][grid[0].length];

        for (Pair house : houseList) {
            bfsToAllPoint(house, grid, sumDistance, visitCount);
        }

        int minSum = Integer.MAX_VALUE;
        boolean finished = false;
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == EMPTY && visitCount[i][j] == houseList.size()) {
                    minSum = Math.min(minSum, sumDistance[i][j]);
                    finished = true;
                }
            }
        }

        if (finished) {
            return minSum;
        }

        return -1;
    }


    public void bfsToAllPoint(Pair house, 
                              int[][] grid,
                              int[][] sumDistance,
                              int[][] visitCount) {

        Queue<Pair> houseQueue = new LinkedList<Pair>();
        boolean[][] isVisited = new boolean[grid.length][grid[0].length];

        houseQueue.offer(house);
        isVisited[house.n][house.m] = true;

        int count = 0;
        while (!houseQueue.isEmpty()) {
            int size = houseQueue.size();
            count++;
            for (int i = 0; i < size; i++) {
                Pair cur = houseQueue.poll();
                for (int j = 0; j < 4; j++) {
                    Pair neighbor = new Pair(
                            cur.n + deltaN[j],
                            cur.m + deltaM[j]
                        );

                    if (!isInbound(neighbor, grid)) {
                        continue;
                    }

                    if (isVisited[neighbor.n][neighbor.m]) {
                        continue;
                    }

                    isVisited[neighbor.n][neighbor.m] = true;
                    sumDistance[neighbor.n][neighbor.m] += count;
                    visitCount[neighbor.n][neighbor.m]++;
                    houseQueue.offer(neighbor);
                }
            }
        }

    }

    public boolean isInbound(Pair pair, int[][] grid) {
        if (pair.n < 0 || pair.n >= grid.length) {
            return false;
        }

        if (pair.m < 0 || pair.m >= grid[0].length) {
            return false;
        }

        return grid[pair.n][pair.m] == EMPTY;
    }
}

results matching ""

    No results matching ""