leetcode-最小高度树

115 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情

题目描述

树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,一个任何没有简单环路的连通图都是一棵树。

给你一棵包含 n 个节点的树,标记为 0 到 n - 1 。给定数字 n 和一个有 n - 1 条无向边的 edges 列表(每一个边都是一对标签),其中 edges[i] = [ai, bi] 表示树中节点 ai 和 bi 之间存在一条无向边。

可选择树中任何一个节点作为根。当选择节点 x 作为根节点时,设结果树的高度为 h 。在所有可能的树中,具有最小高度的树(即,min(h))被称为 最小高度树 。

请你找到所有的 最小高度树 并按 任意顺序 返回它们的根节点标签列表。

树的 高度 是指根节点和叶子节点之间最长向下路径上边的数量。

示例 1:
示例1.jpg 输入:n = 4, edges = [[1,0],[1,2],[1,3]]
输出:[1]
解释:如图所示,当根是标签为 1 的节点时,树的高度是 1 ,这是唯一的最小高度树。

示例 2:
示例2.jpg 输入:n = 6, edges = [[3,0],[3,1],[3,2],[3,4],[5,4]]
输出:[3,4]

思路

输入起始是一张联通图,要转换成最小高度的树根节点,本质上就是找到最长链,最长链的中心节点就是我们要求的解(注意,当最长链的长度为偶数的时候,中心节点有2个)。

怎么求出中心节点,这里介绍1种易于理解的方法:
我们把度为1的节点定义为叶子节点,每次都砍掉联通图中度为1的节点,直到不能再砍,就是我们要求的中心节点。按照这样砍,最后的节点数肯定不会大于2,可以使用反证法来证明:假设最后剩余3个节点,由于初始图是联通图,每次砍掉的都是度为1的叶子节点,所以砍掉n轮后,图还是联通的,如果存在3个节点,必然存在1个节点的度=2,由于没有简单环路,所以此时肯定另外2个节点度为1,还可以继续砍。

最长链的节点数是偶数的情况:
最长链偶数.png

最长链的节点数是奇数的情况,下图第1轮砍掉1、2、5,第2轮砍掉0、4:
最长链奇数.png

Java版本代码

class Solution {
    public List<Integer> findMinHeightTrees(int n, int[][] edges) {
        if (n == 1) {
            List<Integer> list = new ArrayList<>();
            list.add(0);
            return list;
        }
        Queue<Integer> q = new ArrayDeque<>();
        List<Integer>[] linkList = new List[n];
        for (int i = 0; i < n; i++) {
            linkList[i] = new ArrayList<>();
        }
        int[] degree = new int[n];
        for (int[] edge:edges) {
            int s = edge[0];
            int e = edge[1];
            degree[s]++;
            degree[e]++;
            linkList[s].add(e);
            linkList[e].add(s);
        }
        for (int i = 0; i < n; i++) {
            if (degree[i] == 1) {
                q.offer(i);
            }
        }
        int last = n;
        while (!q.isEmpty()) {
            if (last <= 2) {
                return new ArrayList<>(q);
            }
            int size = q.size();
            while (size-- > 0) {
                int node = q.poll();
                last--;
                for (Integer other : linkList[node]) {
                    if (--degree[other] == 1) {
                        q.offer(other);
                    }
                }
            }
        }
        return null;
    }
}