LC.P310[最小高度树]
题目描述
树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,一个任何没有简单环路的连通图都是一棵树。
给你一棵包含 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]
提示:
1 <= n <= 2 * 104
edges.length == n - 1
0 <= ai, bi < n
ai != bi
- 所有
(ai, bi)
互不相同
- 给定的输入 保证 是一棵树,并且 不会有重复的边
方法一:BFS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| class Solution { public List<Integer> findMinHeightTrees(int n, int[][] edges) { List<Integer> ans = new ArrayList<>(); if (n == 1) { ans.add(0); return ans; } int[] parent = new int[n]; Arrays.fill(parent, -1); List<Integer>[] list = new List[n]; for (int i = 0; i < n; ++i) list[i] = new ArrayList<>(); for (int[] edge : edges) { list[edge[0]].add(edge[1]); list[edge[1]].add(edge[0]); } int x = getLongestNode(0, parent, list); int y = getLongestNode(x, parent, list); List<Integer> path = new ArrayList<>(); parent[x] = -1; while (y != -1) { path.add(y); y = parent[y]; } int d = path.size(); if (d % 2 == 0) ans.add(path.get(d / 2 - 1)); ans.add(path.get(d / 2)); return ans; }
private int getLongestNode(int target, int[] parent, List<Integer>[] list) { int n = list.length; Deque<Integer> queue = new ArrayDeque<>(); boolean[] visited = new boolean[n]; queue.offer(target); visited[target] = true; int node = -1; while (!queue.isEmpty()) { int cur = queue.poll(); node = cur; for (int v : list[cur]) { if (!visited[v]) { visited[v] = true; parent[v] = cur; queue.offer(v); } } } return node; } }
|
- 时间复杂度:$O(n)$
- 空间复杂度:$O(n)$
方法二:DFS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| class Solution { public List<Integer> findMinHeightTrees(int n, int[][] edges) { List<Integer> ans = new ArrayList<>(); if (n == 1) { ans.add(0); return ans; } int[] parent = new int[n]; Arrays.fill(parent, -1); List<Integer>[] list = new List[n]; for (int i = 0; i < n; i++) { list[i] = new ArrayList<>(); } for (int[] edge : edges) { list[edge[0]].add(edge[1]); list[edge[1]].add(edge[0]); } int x = getLongestNode(0, parent, list); int y = getLongestNode(x, parent, list); List<Integer> path = new ArrayList<>(); parent[x] = -1; while (y != -1) { path.add(y); y = parent[y]; } int d = path.size(); if (d % 2 == 0) ans.add(path.get(d / 2 - 1)); ans.add(path.get(d / 2)); return ans; }
private int getLongestNode(int target, int[] parent, List<Integer>[] list) { int n = list.length; int[] dist = new int[n]; Arrays.fill(dist, -1); dist[target] = 0; dfs(target, dist, parent, list); int maxDist = 0, node = -1; for (int i = 0; i < n; i++) { if (dist[i] > maxDist) { maxDist = dist[i]; node = i; } } return node; }
private void dfs(int target, int[] dist, int[] parent, List<Integer>[] list) { for (int v : list[target]) { if (dist[v] < 0) { dist[v] = dist[target] + 1; parent[v] = target; dfs(v, dist, parent, list); } } } }
|
- 时间复杂度:$O(n)$
- 空间复杂度:$O(n)$
方法三:拓扑排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class Solution { public List<Integer> findMinHeightTrees(int n, int[][] edges) { List<Integer> ans = new ArrayList<>(); if (n == 1) { ans.add(0); return ans; } int[] degree = new int[n]; List<Integer>[] g = new List[n]; Arrays.setAll(g, k -> new ArrayList<>()); for (int[] e : edges) { g[e[0]].add(e[1]); g[e[1]].add(e[0]); ++degree[e[0]]; ++degree[e[1]]; } Deque<Integer> queue = new ArrayDeque<>(); for (int i = 0; i < n; i++) { if (degree[i] == 1) queue.offer(i); } int remainNodes = n; while (remainNodes > 2) { int size = queue.size(); remainNodes -= size; for (int i = 0; i < size; i++) { int cur = queue.poll(); for (int v : g[cur]) { if (--degree[v] == 1) queue.offer(v); } } } while (!queue.isEmpty()) ans.add(queue.poll()); return ans; } }
|
- 时间复杂度:$O(n)$
- 空间复杂度:$O(n)$