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;
}
}
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。