对于一个具有树特征的无向图,我们可选择任何一个节点作为根。图因此可以成为树,在所有可能的树中,具有最小高度的树被称为最小高度树。给出这样的一个图,写出一个函数找到所有的最小高度树并返回他们的根节点。
格式
该图包含 n 个节点,标记为 0 到 n - 1。给定数字 n 和一个无向边 edges 列表(每一个边都是一对标签)。
你可以假设没有重复的边会出现在 edges 中。由于所有的边都是无向边, [0, 1]和 [1, 0] 是相同的,因此不会同时出现在 edges 里。
示例 1:
输入: n = 4, edges = [[1, 0], [1, 2], [1, 3]]
0
|
1
/ \
2 3
输出: [1]
示例 2:
输入: n = 6, edges = [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]]
0 1 2
\ | /
3
|
4
|
5
输出: [3, 4]
说明:
根据树的定义,树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,一个任何没有简单环路的连通图都是一棵树。
树的高度是指根节点和叶子节点之间最长向下路径上边的数量。
思路 拓扑序列 每次除去度为1 的节点 最后剩下的节点就是生成树的根节点
class Solution {
public List<Integer> findMinHeightTrees(int n, int[][] edges) {
List<Integer> ans = new ArrayList<Integer>();
//建立一个 存放点信息的 list
List<List<Integer>> map = new ArrayList<>();
if (n == 1){
ans.add(0);
return ans;
}
// 有n个节点 所以进行初始化
for (int i=0;i<n;i++) {
map.add(new ArrayList<>());
}
// 每个节点都有一个度
int [] degree = new int [n];
// edgs[0] 代表第一组 边 edgs[0][0] :第一组边的第一个节点 edgs[0][1] :第一组边中的第二个节点
for(int i=0;i<edges.length;i++){
//每次通过 edges[i] 拿到的是一组边
// 找到对应的点 度数++
degree[edges[i][0]]++;
degree[edges[i][1]]++;
//将每个点 放入map中 加入其相邻点队 ?? 这一步意义何为
map.get(edges[i][0]).add(edges[i][1]);
map.get(edges[i][1]).add(edges[i][0]);
}
// bfs 必备队列
Queue<Integer> queue = new LinkedList<>();
// 3.在队列中加入第一个满足条件的元素
for (int i = 0;i < n;i++){
if (degree[i] == 1){//度数为1,说明是叶子结点,入队列
queue.offer(i);
}
}
//进入while循环 剪枝更新
while(!queue.isEmpty()){
//初始化 ans
ans=new ArrayList<>();
//对现在所有队列中元素进行出队列 删除的操作 同时更新 其相邻的节点的度
int size = queue.size();
//此处不能使用 i<queue.size() 作为 循环条件 因为 在i=0 进入到 循环体中后 queue的size 会被减少 其实使用while(queue.isEmpty()) 更好
for(int i=0 ; i<size; i++){
int temp = queue.poll();
ans.add(temp);
// 获得当前节点的相邻节点
List<Integer> nexts = map.get(temp);
for(Integer next : nexts){
degree[next]--;
if(degree[next]==1){
//加入进队列
queue.offer(next);
}
}
}
}
System.out.println("ans is "+ ans);
return ans;
}
}