Minimum Height Trees | LeetCode

For a undirected graph with tree characteristics, we can choose any node as the root. The result graph is then a rooted tree. Among all possible rooted trees, those with minimum height are called minimum height trees (MHTs). Given such a graph, write a function to find all the MHTs and return a list of their root labels.

Format
The graph contains n nodes which are labeled from 0 to n - 1. You will be given the number n and a list of undirected edges (each edge is a pair of labels).

You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.

Example 1:

Given n = 4edges = [[1, 0], [1, 2], [1, 3]]

        0
        |
        1
       / \
      2   3

return [1]

理解题意:题目的意思是给定一个无向连接图,从中选取一个节点作为root,看做一颗树,返回最小高度的树节点。

当只有一个节点的时候,即n==1,那么就可以直接返回;

当只有两个节点的时候,即n==2,那么这两个节点都是符合条件的,任意一个作为root节点,高度都是一样的,所以需要返回这两个节点。

当n>2时候,必然就会存在叶子节点和中间节点的区别,所谓的叶子节点就是只有一个节点与之连接,中间节点就是至少存在两个节点与之相连接。如果选取叶子节点为root,这样的树高度为height = 1+height(中间节点)。很显然,得到的树高度会大于中间节点。所以按照题意,我们只需要选取中间节点,然后遍历,深度搜索,就能够获得最小高度树的root节点,线性复杂度。

不过可以根据图论的一些知识,来简化本题的解法。逐步的删除叶子节点,最后剩余的一个或者两就是答案。这里应该说明的问题的是,符合条件的节点最多只有两个,为什么呢?

假设存在三个点,说明以这三个点为root的树高度是一样的,就是到达最远叶子节点的路径长度是一样的,现在我们逐步删除叶子节点,这样三个点为root的树高度应该逐步减1,最后如果高度都减为0,说明有三个根节点也就是三棵树,这三个节点是独立的,违背了树的定义。下面给出C++实现代码:

  struct Node{
            unordered_set<int> neighbor;
            bool isLeaf()const{return neighbor.size()==1;}
        };
    vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
            vector<int> pB1;
            vector<int> pB2;
            if(n==1){
                pB1.push_back(0);
                return pB1;
            }
            if(n==2){
                pB1.push_back(0);
                pB1.push_back(1);
                return pB1;
            }


            // build the graph
            vector<Node> nodes(n);
            for(auto p:edges){
                nodes[p.first].neighbor.insert(p.second);
                nodes[p.second].neighbor.insert(p.first);
            }


            // find all leaves
            for(int i=0; i<n; ++i){
                if(nodes[i].isLeaf()) 
                    pB1.push_back(i);
            }


            // remove leaves layer-by-layer            
            while(true){
                for(int i : pB1){
                    //下面这个循环体应该只会执行一次,因为是叶子节点,只有一个邻接节点
                    for(auto j: nodes[i].neighbor){
                        //删除叶子节点,同时记录因此产生的新一轮的叶子节点
                        nodes[j].neighbor.erase(i);
                        if(nodes[j].isLeaf()) 
                            pB2.push_back(j);
                    }
                }
                if(pB2.empty()){
                    return pB1;
                }
                pB1.clear();
                swap(pB1, pB2);
            }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值