本篇文章介绍一种简单类型的「最短路径」算法
提到「最短路径」算法,首先可以想到的肯定是「Dijkstra 算法」,但是「Dijkstra 算法」一般适用于有权值且权值为正的情况。关于「Dijkstra 算法」详细实现可见 最短路径-Dijkstra
而我们今天要介绍的题目是无权值的类型,所以如果使用「Dijkstra 算法」,就略显复杂了!!
同时,对于「Dijkstra 算法」,一般计算的是其他所有点到起点的距离;而有些题目仅仅只需要计算两个点的距离而已!
对于今天的问题,有两个前提条件「没有两棵树的高度是相同的」且「需要按照树的高度从低向高砍掉所有的树」
所以我们只需要对所有树的高度升序排列,然后依次计算两点之间的距离即可!!最后我们的问题就抽象成「计算两点之间的距离」
整理一下这个问题的特点
我们可以使用 BFS 一层一层的向外扩张,每扩张一层,距离 ➕1。如下图:
当我们在向外扩张时,记录一下层数,就可以得到两点之间的距离
class Solution { private int m; private int n; private int[][] graph; // 记录所有的树,其三元组为 [h, i, j] private List<int[]> tree = new ArrayList<>(); private int[][] dirs = new int[][]{ {0,1},{0,-1},{1,0},{-1,0} }; public int cutOffTree(List<List<Integer>> forest) { m = forest.size(); n = forest.get(0).size(); graph = new int[m][n]; if (forest.get(0).get(0) == 0) return -1; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { graph[i][j] = forest.get(i).get(j); // 加入 tree 中 if (graph[i][j] > 1) tree.add(new int[]{graph[i][j], i, j}); } } // 根据 h 排序 Collections.sort(tree, Comparator.comparingInt(o -> o[0])); int ans = 0; int x = 0, y = 0; for (int[] t : tree) { int nx = t[1], ny = t[2]; int dist = bfs(x, y, nx, ny); if (dist == -1) return -1; ans += dist; x = nx; y = ny; } return ans; } private int bfs(int X, int Y, int P, int Q) { if (X == P && Y == Q) return 0; // 记录节点访问情况 boolean[][] visited = new boolean[m][n]; // 双端队列 Deque<int[]> deque = new ArrayDeque<>(); deque.addLast(new int[]{X, Y}); visited[X][Y] = true; int dist = 0; while (!deque.isEmpty()) { int size = deque.size(); for (int i = 0; i < size; i++) { int[] cur = deque.pollFirst(); int x = cur[0], y = cur[1]; for (int[] dir : dirs) { int nx = x + dir[0], ny = y + dir[1]; // 非法情况 if (nx < 0 || nx >= m || ny < 0 || ny >= n || graph[nx][ny] == 0 || visited[nx][ny]) continue; // 达到终点 if (nx == P && ny == Q) return dist + 1; deque.addLast(new int[]{nx, ny}); visited[nx][ny] = true; } } dist++; } return -1; }}