树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,一个任何没有简单环路的连通图都是一棵树。
给你一棵包含 n
个节点的树,标记为 0
到 n - 1
。给定数字 n
和一个有 n - 1
条无向边的 edges
列表(每一个边都是一对标签),其中 edges[i] = [ai, bi]
表示树中节点 ai
和 bi
之间存在一条无向边。
可选择树中任何一个节点作为根。当选择节点 x
作为根节点时,设结果树的高度为 h
。在所有可能的树中,具有最小高度的树(即,min(h)
)被称为 最小高度树 。
请你找到所有的 最小高度树 并按 任意顺序 返回它们的根节点标签列表。
树的 高度 是指根节点和叶子节点之间最长向下路径上边的数量。
示例 1:
输入:n = 4, edges = [[1,0],[1,2],[1,3]] 输出:[1] 解释:如图所示,当根是标签为 1 的节点时,树的高度是 1 ,这是唯一的最小高度树。
示例 2:
输入:n = 6, edges = [[3,0],[3,1],[3,2],[3,4],[5,4]] 输出:[3,4]
题解:对于树结构,这题主要的问题是如何求解树的深度。然后对每一个节点当根节点进行依次求解,然后比较大小。对于树的深度,我们可以使用深度优先遍历和广度优先遍历,原理都是一样的。在此以广度优先遍历为例,准备一个队列,存储兄弟节点的信息,然后要确保每一个节点都要访问而且不能重复访问,可以使用一个数组统计每个节点是否已访问。这就是这题的暴力求解,优化算法自己理解不了。(现在Leetcode的中等题已经这样着了。。。。)
class Solution {
public static List<Integer> findMinHeightTrees(int n, int[][] edges) {
List<Integer> target = new ArrayList<>();
ArrayList<Integer>[] lists = new ArrayList[n];
for (int[] edge : edges) {
ArrayList<Integer> tmp0 = lists[edge[0]];
ArrayList<Integer> tmp1 = lists[edge[1]];
if (tmp0 == null) {
tmp0 = new ArrayList<Integer>();
lists[edge[0]] = tmp0;
}
tmp0.add(edge[1]);
if (tmp1 == null) {
tmp1 = new ArrayList<Integer>();
lists[edge[1]] = tmp1;
}
tmp1.add(edge[0]);
}
for (int i = 0; i < n; i++) {
Queue<Integer> queue = new PriorityQueue<>();
queue.add(i);
int[] visted = new int[n];
//记录当前层
Map<Integer, Integer> map = new HashMap<>();
map.put(i, 1);
int Height = 0;
while (!queue.isEmpty()) {
Integer poll = queue.poll();
if(visted[poll]!=1) {
ArrayList<Integer> list = lists[poll];
if (list != null) {
for (Integer t : list) {
if(visted[t]!=1) {
queue.add(t);
map.put(t, map.get(poll) + 1);
Height = Math.max(Height, map.get(poll) + 1);
}
}
}
}
visted[poll] = 1;
}
if (target.isEmpty()) {
target.add(Height);
target.add(i);
} else {
Integer i1 = target.get(0);
if(i1==Height)
target.add(i);
else if (i1 > Height) {
target.clear();
target.add(Height);
target.add(i);
}
}
}
target.remove(0);
return target;
}
}
官方解答是先证明树中的最长两个结点,根节点一定在这两个结点的路径上。在此就不贴官方代码了,大家感兴趣的可以去看看。