题目地址:
https://www.lintcode.com/problem/minimum-height-trees/description
给定一个 n n n阶无向图,其有树性质。若取其中某个顶点为根,其就成为一棵有根树,从而有树高。求使得树高最小的顶点编号。答案也许不唯一。
思路是BFS。像剥洋葱一样从最外层度为 1 1 1的顶点一层一层向里面剥,最后一层剥掉的皮就是答案。证明和详细解释可以参考https://blog.csdn.net/qq_46105170/article/details/108427561。代码如下:
import java.util.*;
public class Solution {
/**
* @param n: n nodes labeled from 0 to n - 1
* @param edges: a undirected graph
* @return: a list of all the MHTs root labels
*/
public List<Integer> findMinHeightTrees(int n, int[][] edges) {
// Wirte your code here
List<Integer> res = new ArrayList<>();
// 特判一下平凡图,其没有度为1的顶点
if (n == 1) {
res.add(0);
return res;
}
// 邻接表建图,并且得到每个顶点的度
Map<Integer, Set<Integer>> graph = buildGraph(edges);
int[] degrees = getDegrees(n, edges);
// 将度为1的顶点入队
Queue<Integer> queue = new LinkedList<>();
for (int i = 0; i < degrees.length; i++) {
if (degrees[i] == 1) {
queue.offer(i);
}
}
while (!queue.isEmpty()) {
// 把当前层的顶点都加入进答案。等到队列空的时候,最后那一层就是要求的答案
res.clear();
res.addAll(queue);
// 由于是分层遍历,所以要记录队列的size
int size = queue.size();
for (int i = 0; i < size; i++) {
int cur = queue.poll();
for (int next : graph.get(cur)) {
degrees[next]--;
if (degrees[next] == 1) {
queue.offer(next);
}
}
}
}
return res;
}
private int[] getDegrees(int n, int[][] edges) {
int[] degrees = new int[n];
for (int[] edge : edges) {
degrees[edge[0]]++;
degrees[edge[1]]++;
}
return degrees;
}
private Map<Integer, Set<Integer>> buildGraph(int[][] edges) {
Map<Integer, Set<Integer>> graph = new HashMap<>();
for (int[] edge : edges) {
graph.computeIfAbsent(edge[0], k -> new HashSet<>()).add(edge[1]);
graph.computeIfAbsent(edge[1], k -> new HashSet<>()).add(edge[0]);
}
return graph;
}
}
时空复杂度 O ( n ) O(n) O(n)。