LeetCode 310. Minimum Height Trees - 拓扑排序(Topological Sort)系列题9

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.

Given a tree of n nodes labelled from 0 to n - 1, and an array of n - 1 edges where edges[i] = [ai, bi] indicates that there is an undirected edge between the two nodes ai and bi in the tree, you can choose any node of the tree as the root. When you select a node x as the root, the result tree has height h. Among all possible rooted trees, those with minimum height (i.e. min(h))  are called minimum height trees (MHTs).

Return a list of all MHTs' root labels. You can return the answer in any order.

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

Example 1:

Input: n = 4, edges = [[1,0],[1,2],[1,3]]
Output: [1]
Explanation: As shown, the height of the tree is 1 when the root is the node with label 1 which is the only MHT.

Example 2:

Input: n = 6, edges = [[3,0],[3,1],[3,2],[3,4],[5,4]]
Output: [3,4]

Example 3:

Input: n = 1, edges = []
Output: [0]

Example 4:

Input: n = 2, edges = [[0,1]]
Output: [0,1]

Constraints:

  • 1 <= n <= 2 * 104
  • edges.length == n - 1
  • 0 <= ai, bi < n
  • ai != bi
  • All the pairs (ai, bi) are distinct.
  • The given input is guaranteed to be a tree and there will be no repeated edges.

这题给的是无向图,很难想到用拓扑排序(Topological Sort)法,但仔细分析题目会发现其实可以拓扑排序的思想来解答。

题目说无向图满足一棵树的条件,即所有节点连通且不存在环。可以直观的看出只有一条边的点肯定是树的页节点,如果树中的节点大于等于3个,那么叶节点就不可能是根节点,根节点肯定是所有叶节点之间的某一个节点。

假设根节点确定了,那么它到各个叶节点的距离也就确定,如果我们把所有叶节点砍掉,那旧叶节点的父节点就变成了新叶节点,根节点到新叶节点的距离也是确定的,因此根节点仍然不变,树的高度减1。每次把所有叶节点都砍掉,到最后将剩下1个或2个节点,这1个或2个节点就是根节点。为什么最后最多是2个根节点呢?可以用反证法,假如有3个根节点使得树有同样的最小高度,那当只剩3个节点时,由于3个都是根节点,那么它们互相之间的距离必须要相等,这样就形成了一个环,跟一棵树不能有环相矛盾了。

由于是无向图,因此在代码实现时引入度degree的概念(不是入度或出度),每遇到一条边,它的两个顶点的度degree加1。最后度degree为1的点就是叶节点。

class Solution:
    def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]:
        degree = [0] * n
        graph = [[] for _ in range(n)]
        cnt = n
        
        for (u, v) in edges:
            degree[u] += 1
            degree[v] += 1
            graph[u].append(v)
            graph[v].append(u)
        
        q = deque()
        
        for i in range(n):
            if degree[i] <= 1:
                q.append(i)
        
        while cnt > 2:
            qsize = len(q)
            for _ in range(qsize):
                u = q.popleft()
                cnt -= 1
                for v in graph[u]:
                    degree[v] -= 1
                    if degree[v] == 1:
                        q.append(v)
        
        res = []
        while q:
            res.append(q.popleft())
        
        return res

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值