题目地址:
https://www.lintcode.com/problem/build-post-office-ii/description
给定一个二维矩阵,里面有数字 0 , 1 , 2 0,1,2 0,1,2, 0 0 0代表空地, 1 1 1代表房子, 2 2 2代表障碍物。问哪个地方盖办公室,可以使得办公室离所有房子的最短距离和是最小的,返回那个最短距离。这里的距离指的是,从房子到办公室的所有每一步只能上下左右走一步、并且不能走到障碍物和房子上的路径中,步数最少的路径的那个步数。如果答案不存在则返回 − 1 -1 −1。
思路是BFS。直接枚举每个
0
0
0,然后用BFS的方式算出这个
0
0
0与别的所有
1
1
1的距离。有几个注意的地方:
1、在BFS的时候,只有
0
0
0能入队,
1
1
1和
2
2
2都不能入队。当遍历到
1
1
1的时候要累加距离和;
2、如果发现BFS能访问到的
1
1
1的个数小于总共
1
1
1的个数,则说明这个位置建办公室的话,有的房屋是走不到的,这个位置不合法。
代码如下:
import java.util.*;
public class Solution {
class Pair {
int x, y;
public Pair(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
Pair pair = (Pair) o;
return x == pair.x && y == pair.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
/**
* @param grid: a 2D grid
* @return: An integer
*/
public int shortestDistance(int[][] grid) {
// write your code here
if (grid == null || grid.length == 0 || grid[0].length == 0) {
return -1;
}
// 数一下有多少个房子
int oneCount = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == 1) {
oneCount++;
}
}
}
int res = Integer.MAX_VALUE;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == 0) {
res = Math.min(res, bfs(grid, new Pair(i, j), oneCount));
}
}
}
return res == Integer.MAX_VALUE ? -1 : res;
}
private int bfs(int[][] grid, Pair start, int oneCount) {
Queue<Pair> queue = new LinkedList<>();
queue.offer(start);
Set<Pair> visited = new HashSet<>();
visited.add(start);
int step = 0, disSum = 0;
while (!queue.isEmpty()) {
step++;
int size = queue.size();
for (int i = 0; i < size; i++) {
Pair cur = queue.poll();
for (Pair next : getNexts(cur, grid, visited)) {
visited.add(next);
// 如果是空地,则入队
if (grid[next.x][next.y] == 0) {
queue.offer(next);
}
// 如果是房屋,则累加距离,并且减去房屋数
if (grid[next.x][next.y] == 1) {
disSum += step;
oneCount--;
}
}
}
}
// 如果房屋数位0,说明所有房屋都能被访问,则返回距离和;否则返回无穷大
return oneCount == 0 ? disSum : Integer.MAX_VALUE;
}
private List<Pair> getNexts(Pair cur, int[][] grid, Set<Pair> visited) {
List<Pair> nexts = new ArrayList<>();
int[] d = {1, 0, -1, 0, 1};
for (int i = 0; i < 4; i++) {
int nextX = cur.x + d[i], nextY = cur.y + d[i + 1];
if (0 <= nextX && nextX < grid.length && 0 <= nextY && nextY < grid[0].length && grid[nextX][nextY] != 2) {
Pair next = new Pair(nextX, nextY);
if (!visited.contains(next)) {
nexts.add(next);
}
}
}
return nexts;
}
}
时间复杂度 O ( ( m n ) 2 ) O((mn)^2) O((mn)2)。