题目地址:
https://leetcode.com/problems/cut-off-trees-for-golf-event/
给定一个 m × n m\times n m×n的二维矩阵 A A A, 0 0 0表示障碍物, 1 1 1表示空地,大于 1 1 1的数表示要砍掉的树的高度。一开始从 ( 0 , 0 ) (0,0) (0,0)开始出发,每次只能走到非 0 0 0的位置,并且要按照树的高度从小到大依次走到每一个树将其砍掉。问总共至少要走多少步。如果某棵树走不到,则直接返回 − 1 -1 −1。
可以先将所有的树的位置连同其高度存进一个最小堆,然后依次pop堆顶,接着用BFS求一下从当前位置走到这棵树的最短路,累加步数即可。如果发现走不到,则直接返回 − 1 -1 −1。代码如下:
import java.util.*;
public class Solution {
public int cutOffTree(List<List<Integer>> forest) {
int m = forest.size(), n = forest.get(0).size();
// 第一维存高度,后面两维存树的坐标
PriorityQueue<int[]> minHeap = new PriorityQueue<>((x, y) -> Integer.compare(x[0], y[0]));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int h = forest.get(i).get(j);
if (h > 1) {
minHeap.offer(new int[]{h, i, j});
}
}
}
int res = 0;
int[] cur = {forest.get(0).get(0), 0, 0};
while (!minHeap.isEmpty()) {
int[] next = minHeap.poll();
int steps = bfs(cur, next, forest);
if (steps == -1) {
return -1;
}
res += steps;
cur = next;
}
return res;
}
private int bfs(int[] cur, int[] next, List<List<Integer>> forest) {
if (Arrays.equals(cur, next)) {
return 0;
}
int m = forest.size(), n = forest.get(0).size();
int[] d = {1, 0, -1, 0, 1};
Queue<int[]> queue = new LinkedList<>();
queue.offer(cur);
boolean[][] vis = new boolean[m][n];
vis[cur[1]][cur[2]] = true;
int res = 0;
while (!queue.isEmpty()) {
res++;
int size = queue.size();
for (int i = 0; i < size; i++) {
cur = queue.poll();
for (int j = 0; j < 4; j++) {
int nextX = cur[1] + d[j], nextY = cur[2] + d[j + 1];
if (0 <= nextX && nextX < m && 0 <= nextY && nextY < n) {
if (nextX == next[1] && nextY == next[2]) {
return res;
}
int h = forest.get(nextX).get(nextY);
if (h >= 1 && !vis[nextX][nextY]) {
queue.offer(new int[]{h, nextX, nextY});
vis[nextX][nextY] = true;
}
}
}
}
}
return -1;
}
}
时间复杂度 O ( k ( m n + log k ) ) O(k(mn+\log k)) O(k(mn+logk)),空间 O ( k + m n ) O(k+mn) O(k+mn), k k k是树的个数。