Leetcode: Minimum Height Trees


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 = 4, edges = [[1, 0], [1, 2], [1, 3]]

        0
        |
        1
       / \
      2   3

return [1]

Example 2:

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

     0  1  2
      \ | /
        3
        |
        4
        |
        5

return [3, 4]

Hint:

Show Hint
  1. How many MHTs can a graph have at most?

Note:

(1) According to the definition of tree on Wikipedia: “a tree is an undirected graph in which any two vertices are connected by exactly one path. In other words, any connected graph without simple cycles is a tree.”

(2) The height of a rooted tree is the number of edges on the longest downward path between the root and a leaf.

一个图最多有两个MHT树,为距离最长的两个节点的中点。关键是怎么找出这两个相聚最远的节点。1)任选一个节点做遍历,找到距离最远的点;那么这个点是相聚最远的节点之一。2)从这个节点再做遍历,找到另外一个距离最远的节点。遍历过程中保存路径(前序),然后可以找到中点。

class Solution {
public:
    vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
        if (n <= 0) {
            return vector<int>();
        }
        
        vector<set<int>> nodeEdges(n);
        for (const auto& edge : edges) {
            nodeEdges[edge.first].emplace(edge.second);
            nodeEdges[edge.second].emplace(edge.first);
        }
        
        vector<int> distance(n);
        vector<int> prevNodes(n);
        bfs(nodeEdges, 0, distance, prevNodes);
        int node1st = 0;
        for (int i = 1; i < n; ++i) {
            if (distance[i] > distance[node1st]) {
                node1st = i;
            }
        }
        
        bfs(nodeEdges, node1st, distance, prevNodes);
        int node2nd = 0;
        for (int i = 1; i < n; ++i) {
            if (distance[i] > distance[node2nd]) {
                node2nd = i;
            }
        }
        
        vector<int> longestPath;
        while (node2nd != -1) {
            longestPath.push_back(node2nd);
            node2nd = prevNodes[node2nd];
        }
      
        vector<int> result;
        if ((longestPath.size() & 1) == 0) {
            result.push_back(longestPath[longestPath.size() / 2 - 1]);
        }
        result.push_back(longestPath[longestPath.size() / 2]);
        return result;
    }

private:
    void bfs(const vector<set<int>>& nodeEdges, int start, vector<int>& distance, vector<int>& prevNodes) {
        vector<bool> visited(nodeEdges.size(), false);
        queue<int> nodes;
        nodes.push(start);
        distance[start] = 0;
        prevNodes[start] = -1;
        while (!nodes.empty()) {
            int curNode = nodes.front();
            nodes.pop();
            visited[curNode] = true;
            for (const auto& neighbor : nodeEdges[curNode]) {
                if (!visited[neighbor]) {
                    nodes.push(neighbor);
                    distance[neighbor] = distance[curNode] + 1;
                    prevNodes[neighbor] = curNode;
                }
            }
        }
    }
};

另外一种解法类似于拓扑排序,把度为1的节点一层层删除,相当于从边缘向核心推进,最后剩下的1个或者2个节点则为MHT树的根节点。

class Solution {
public:
    vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
        vector<set<int>> nodeEdges(n);
        for (const auto& edge : edges) {
            nodeEdges[edge.first].emplace(edge.second);
            nodeEdges[edge.second].emplace(edge.first);
        }
        
        queue<int> curLeaves;
        for (int i = 0; i < n; ++i) {
            if (nodeEdges[i].size() <= 1) {
                curLeaves.push(i);
            }
        }
        
        if (n > 2) {
            queue<int> nextLeaves;
            while (!curLeaves.empty()) {
                int leaf = curLeaves.front();
                curLeaves.pop();
                --n;
                
                // Leaf node only has one neighbor node
                int neighbor = *(nodeEdges[leaf].begin());
                nodeEdges[neighbor].erase(leaf);
                if (nodeEdges[neighbor].size() == 1) {
                    nextLeaves.push(neighbor);
                }
                
                if (curLeaves.empty() && n > 2) {
                    curLeaves.swap(nextLeaves);
                }
            }
            curLeaves.swap(nextLeaves);
        }
        
        vector<int> result;
        while (!curLeaves.empty()) {
            result.push_back(curLeaves.front());
            curLeaves.pop();
        }
        return result;
    }
};


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值