lintcode 1298 · 最小高度树 【BFS 图】

题目链接、描述

https://www.lintcode.com/problem/1298

对于一个树状的无向图,选择任何一个节点作为根。这个图就变成了一个有根树。在所有可能的有根树中,有最小高度的树叫做最小高度树(minimum height trees, MHTs)。给定这样的图,找出所有的MHTs,返回根标记的数组。

格式
图包含了n个节点,标记从0到n-1。给定n和一个无向边列表edges。每一个边是一组节点标记。

假定没有重复的遍。由于所有的边是无向边,所以[0, 1][1, 0]是等价的,所以也不会同时出现在edges当中。


(1)根据树的定义:一个树是一个无向图,且任意两个顶点都有唯一一条路径连通。也即,树中没有环。
(2)树的高度是树根和叶子之间的最长边数。

样例
样例1

输入: n = 4, edges = [[1, 0], [1, 2], [1, 3]]
输出: [1]
解释:
        0
        |
        1
       / \
      2   3
样例2

输入: n = 6, edges = [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]]
输出: [3, 4]
解释:
     0  1  2
      \ | /
        3
        |
        4
        |
        5

思路

前置知识:图、拓扑排序

这道题可以用拓扑排序的思想来做,虽然不是有序图,但是当节点入度为1时,必然为叶子节点。
由此可见当我们用BFS从叶子节点一层一层搜索下去时,最后一组的节点就是最短高度根节点。
我们的目标是找到那个根节点。

    创建图
    统计每个节点的入度
    把所有入度为1的节点放入queue (叶子节点)
    从每个叶子节点找到他们各自的根节点,把他们的入度减一
    当根节点入度为1时, 放入queue
    最后的一组queue就是最后的根节点, 也就是答案。

代码

public class Solution {
    /**
     * @param n: n nodes labeled from 0 to n - 1
     * @param edges: a undirected graph
     * @return:  a list of all the MHTs root labels
     *          we will sort your return value in output
     */
    public List<Integer> findMinHeightTrees(int n, int[][] edges) {
           /*
        这道题可以用拓扑排序的思想来做,虽然不是有序图,但是当节点入度为1时,必然为叶子节点。
        由此可见当我们用BFS从叶子节点一层一层搜索下去时,最后一组的节点就是最短高度根节点。
        我们的目标是找到那个根节点。

        创建图
        统计每个节点的入度
        把所有入度为1的节点放入queue (叶子节点)
        从每个叶子节点找到他们各自的根节点,把他们的入度减一
        当根节点入度为1时, 放入queue
        最后的一组queue就是最后的根节点, 也就是答案。
         */
        if(edges==null|| edges.length ==0 || edges[0].length ==0 || n ==1)
            return Arrays.asList(0);

        Map<Integer,Node> graph = new HashMap<>(); //图
        for (int i = 0; i <n ; i++) {
           graph.put(i,new Node(i));
        }

        for (int[] edge : edges) {
            int v1 = edge[0],v2 = edge[1];

            Node from = graph.get(v1);
            Node to = graph.get(v2);
            from.nexts.add(to);
            to.nexts.add(from);
            to.in++;
            from.in++;
        }

        Queue<Node> queue = new LinkedList<>(); //宽度优先遍历的核心
        for(int k: graph.keySet()){
            if(graph.get(k).in ==1){

                queue.add(graph.get(k));
            }
        }

       // System.out.println(queue.size());
        List<Integer> ans = new ArrayList<>();//记录最后一组queue的节点值,就是答案
        while (!queue.isEmpty()){
            int size = queue.size();
            ans.clear();
            for (int i = 0; i <size ; i++) {
                Node poll = queue.poll();
                ans.add(poll.data);

                for (Node next : poll.nexts) {
                    if(--next.in ==1){
                        queue.add(next);
                    }
                }
            }

            //System.out.println(ans);
        }
        return ans;
    }


    static class Node{ //图的节点的定义
        int data;
        int in;
        List<Node> nexts;
        public Node(int d){
            data =d;
            in =0;
            nexts = new ArrayList<>();
        }
    }
}

你可能感兴趣的:(宽度优先,算法)