【BFS】310. 最小高度树 1162. 地图分析 (两题都是从多个节点同时开始进行BFS的题目)
310. 最小高度树
题目:
对于一个具有树特征的无向图,我们可选择任何一个节点作为根。图因此可以成为树,在所有可能的树中,具有最小高度的树被称为最小高度树。给出这样的一个图,写出一个函数找到所有的最小高度树并返回他们的根节点。
格式
该图包含 n 个节点,标记为 0 到 n - 1。给定数字 n 和一个无向边 edges 列表(每一个边都是一对标签)。
你可以假设没有重复的边会出现在 edges 中。由于所有的边都是无向边, [0, 1]和 [1, 0] 是相同的,因此不会同时出现在 edges 里。

解答:
思路:
我们从边缘开始,先找到所有出度为1的节点,然后把所有出度为1的节点进队列,然后不断地bfs,最后找到的就是两边同时向中间靠近的节点,那么这个中间节点就相当于把整个距离二分了,那么它当然就是到两边距离最小的点啦,也就是到其他叶子节点最近的节点了
这个方法的正确性说明:
对当前的图(初始的图或者删掉了前几层叶子节点的图),我们要找的满足题设的根节点所在位置只有两种可能,一种在当前图的叶子节点(即度为1的节点),一种为内部节点,若选择某叶子节点1,则该叶子节点1与任意其他叶子节点2的距离必定为叶子1-内部节点x-叶子2,深度为这三段边之和,必大于等于max(内部x-叶子1,内部x-叶子2),所以相比于叶子节点,解空间只能出现在内部节点,每层情况都是这样,所以我们要剥开叶子节点直到再无可分的内部节点为止。
import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Queue; public class FindMinHeightTrees { public List<Integer> findMinHeightTrees(int n, int[][] edges) { List<Integer> res = new ArrayList<>(); /*如果只有一个节点,那么他就是最小高度树*/ if (n == 1) { res.add(0); return res; } /*建立各个节点的出度表*/ int[] degree = new int[n]; /*建立图关系,在每个节点的list中存储相连节点*/ List<List<Integer>> map = new ArrayList<>(); for (int i = 0; i < n; i++) { map.add(new ArrayList<>()); } for (int[] edge : edges) { degree[edge[0]]++; degree[edge[1]]++;/*出度++*/ map.get(edge[0]).add(edge[1]);/*添加相邻节点*/ map.get(edge[1]).add(edge[0]); } /*建立队列*/ Queue<Integer> queue = new LinkedList<>(); /*把所有出度为1的节点,也就是叶子节点入队*/ for (int i = 0; i < n; i++) { if (degree[i] == 1) queue.offer(i); } /*循环条件当然是经典的不空判断*/ while (!queue.isEmpty()) { res = new ArrayList<>();/*这个地方注意,我们每层循环都要new一个新的结果集合, 这样最后保存的就是最终的最小高度树了*/ int size = queue.size();/*这是每一层的节点的数量*/ for (int i = 0; i < size; i++) { int cur = queue.poll(); res.add(cur);/*把当前节点加入结果集,不要有疑问,为什么当前只是叶子节点为什么要加入结果集呢? 因为我们每次循环都会新建一个list,所以最后保存的就是最后一个状态下的叶子节点, 这也是很多题解里面所说的剪掉叶子节点的部分,你可以想象一下图,每层遍历完, 都会把该层(也就是叶子节点层)这一层从队列中移除掉, 不就相当于把原来的图给剪掉一圈叶子节点,形成一个缩小的新的图吗*/ List<Integer> neighbors = map.get(cur); /*这里就是经典的bfs了,把当前节点的相邻接点都拿出来, * 把它们的出度都减1,因为当前节点已经不存在了,所以, * 它的相邻节点们就有可能变成叶子节点*/ for (int neighbor : neighbors) { degree[neighbor]--; if (degree[neighbor] == 1) { /*如果是叶子节点我们就入队*/ queue.offer(neighbor); } } } } return res;/*返回最后一次保存的list*/ } }
1162. 地图分析
题目:
你现在手里有一份大小为 N x N 的 网格 grid,上面的每个 单元格 都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地,请你找出一个海洋单元格,这个海洋单元格到离它最近的陆地单元格的距离是最大的。
我们这里说的距离是「曼哈顿距离」( Manhattan Distance):(x0, y0) 和 (x1, y1) 这两个单元格之间的距离是 |x0 - x1| + |y0 - y1| 。
如果网格上只有陆地或者海洋,请返回 -1。

解答:
class Solution { public int maxDistance(int[][] grid) { int[] dx = {0,0,1,-1}; int[] dy = {1,-1,0,0}; int rows = grid.length, col = grid[0].length; Queue<int[]> queue = new LinkedList<>(); for(int i = 0;i<rows;i++) for(int j = 0;j<col;j++){ if(grid[i][j] == 1){ queue.offer(new int[]{i,j}); } } boolean hasOcean = false; int[] point = null; while(!queue.isEmpty()){ point = queue.poll(); int x = point[0]; int y = point[1]; for(int i = 0;i<4;i++){ int newX = x + dx[i]; int newY = y + dy[i]; if(newX<0 || newX >=rows || newY<0 ||newY >=col||grid[newX][newY]!=0){ continue; } hasOcean = true; grid[newX][newY] = grid[x][y] + 1; queue.offer(new int[]{newX,newY}); } } if(point == null || !hasOcean){ return -1; } return grid[point[0]][point[1]] - 1; } }

浙公网安备 33010602011771号