【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;
    }
}

 

 

 

 

posted @ 2020-09-24 21:25  3KBLACK  阅读(105)  评论(0)    收藏  举报