Build Post Office

Problem

Given a 2D grid, each cell is either an house 1 or empty 0 (the number zero, one), find the place to build a post office, the distance that post office to all the house sum is smallest. Return the smallest distance. Return -1 if it is not possible.

Notice

You can pass through house and empty.
You only build post office on an empty.

Example

Given a grid:

0 1 0 0
1 0 1 1
0 1 0 0
return 6. (Placing a post office at (1,1), the distance that post office to all the house sum is smallest.)

Solution

DP

会超时。

public class Solution {
    public class Node {
        int x;
        int y;
        public Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    public int shortestDistance(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) return -1;
        ArrayList<Node> house = new ArrayList<>();
        ArrayList<Node> empty = new ArrayList<>();
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == 1) {
                    house.add(new Node(i, j));
                }
                else {
                    empty.add(new Node(i, j));
                }
            }
        }
        if (empty.size() == 0) return -1;
        int min = Integer.MAX_VALUE;
        for (Node node: empty) {
            min = Math.min(min, helper(house, node));
        }
        return min;
    }
    private int helper(ArrayList<Node> house, Node node) {
        int dist = 0;
        for (Node cur: house) {
            dist += Math.abs(cur.x - node.x) + Math.abs(cur.y - node.y);
        }
        return dist;
    }
}
public class Solution {
    public int shortestDistance(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        if (grid == null || m == 0 || n == 0) return -1;
        List<Integer> x = new ArrayList<>();
        List<Integer> y = new ArrayList<>();
        List<Integer> xSum = new ArrayList<>();
        List<Integer> ySum = new ArrayList<>();
        int res = Integer.MAX_VALUE;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) {
                    x.add(i);
                    y.add(j);
                }
            }
        }
        Collections.sort(x);
        Collections.sort(y);
        int total = x.size();
        xSum.add(0);
        ySum.add(0);
        for (int i = 1; i <= total; i++) {
            xSum.add(xSum.get(i-1) + x.get(i-1));
            ySum.add(ySum.get(i-1) + y.get(i-1));
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 0) {
                    int costX = getCost(x, xSum, i, total);
                    int costY = getCost(y, ySum, j, total);
                    if (costX + costY < res) res = costX + costY;
                }
            }
        }
        return res;
        
    }
    public int getCost(List<Integer> list, List<Integer> sum, int pos, int size) {
        if (size == 0) return 0;
        if (list.get(0) > pos) return sum.get(size) - pos * size;
        int l = 0, r = size-1;
        while (l + 1 < r) {
            int mid = l + (r-l)/2;
            if (list.get(mid) <= pos) l = mid;
            else r = mid-1;
        }
        int index = 0;
        if (list.get(r) <= pos) index = r;
        else index = l;
        return sum.get(size) - sum.get(index+1) - pos * (size-index-1) + pos * (index+1) - sum.get(index+1);
    }
}

Build Post Office II

Problem

Given a 2D grid, each cell is either a wall 2, an house 1 or empty 0 (the number zero, one, two), find the place to build a post office, the distance that post office to all the house sum is smallest. Return the smallest distance. Return -1 if 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.

Example

Given a grid:

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

return 8, 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.)

Challenge

Solve this problem within O(n^3) time.

Solution

public class Solution {
    class Node {
        int x, y, dist;
        public Node(int x, int y, int dist) {
            this.x = x;
            this.y = y;
            this.dist = dist;
        }
    }
    public int shortestDistance(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) return -1;
        int m = grid.length;
        int n = grid[0].length;
        List<Node> house = new ArrayList<>();
        List<Node> empty = new ArrayList<>();
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) house.add(new Node(i, j, 0));
                else if (grid[i][j] == 0) empty.add(new Node(i, j, 0));
            }
        }
        if (empty.size() == 0) return -1;
        int k = house.size();
        int[][][] distance = new int[k][m][n];
        for (int i = 0; i < k; i++) {
            for (int j = 0; j < m; j++) {
                Arrays.fill(distance[i][j], Integer.MAX_VALUE);
            }
        }
        boolean[][] visited;
        for (int i = 0; i < k; i++) {
            visited = new boolean[m][n];
            getDistance(house.get(i), distance, i, grid, visited);
        }
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 0) {
                    int sum = 0;
                    for (int l = 0; l < k; l++) {
                        if (distance[l][i][j] == Integer.MAX_VALUE) {
                            sum = Integer.MAX_VALUE;
                            break;
                        }
                        sum += distance[l][i][j];
                    }
                    min = Math.min(min, sum);
                }
            }
        }
        if (min == Integer.MAX_VALUE) return -1;
        return min;
    }
    int[] dx = {-1, 1, 0, 0};
    int[] dy = {0, 0, -1, 1};
    private void getDistance(Node cur, int[][][] distance, int k, int[][] grid, boolean[][] visited) {
        Queue<Node> q = new LinkedList<Node>();
        q.offer(cur);
        visited[cur.x][cur.y] = true;
        int m = grid.length;
        int n = grid[0].length;
        while (!q.isEmpty()) {
            Node now = q.poll();
            for (int i = 0; i < 4; i++) {
                int nextX = now.x + dx[i];
                int nextY = now.y + dy[i];
                if (nextX >= 0 && nextX < m && nextY >= 0 && nextY < n && grid[nextX][nextY] == 0 && !visited[nextX][nextY]) {
                    distance[k][nextX][nextY] = now.dist + 1;
                    q.add(new Node(nextX, nextY, now.dist+1));
                    visited[nextX][nextY] = true;
                }
            }
        }
    }
}

linspiration
161 声望53 粉丝