LeetCode 310. Minimum Height Trees(最小高度树)
来源:互联网 发布:cv source数据库 复旦 编辑:程序博客网 时间:2024/05/20 06:50
原题网址:https://leetcode.com/problems/minimum-height-trees/
For a undirected graph with tree characteristics, we can choose any node as the root. The result graph is then a rooted tree. Among all possible rooted trees, those with minimum height are called minimum height trees (MHTs). Given such a graph, write a function to find all the MHTs and return a list of their root labels.
Format
The graph contains n
nodes which are labeled from 0
to n - 1
. You will be given the number n
and a list of undirected edges
(each edge is a pair of labels).
You can assume that no duplicate edges will appear in edges
. Since all edges are undirected, [0, 1]
is the same as [1, 0]
and thus will not appear together in edges
.
Example 1:
Given n = 4
, edges = [[1, 0], [1, 2], [1, 3]]
0 | 1 / \ 2 3
return [1]
Example 2:
Given n = 6
, edges = [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]]
0 1 2 \ | / 3 | 4 | 5
return [3, 4]
Hint:
- How many MHTs can a graph have at most?
Note:
(1) According to the definition of tree on Wikipedia: “a tree is an undirected graph in which any two vertices are connected by exactly one path. In other words, any connected graph without simple cycles is a tree.”
(2) The height of a rooted tree is the number of edges on the longest downward path between the root and a leaf.
方法一:最小高度树的根一定在图的一条最长路径的中间,寻找这条最长路径的方法是从任意一点出发,找到最远的点,然后再从这个最远的点出发,找到离它最远的点。可以用广度优先或者深度优先搜索。public class Solution { private int maxNode, maxDepth; private void dfs(int from, int depth, List<Integer>[] graph, boolean[] visited, int[] dist, int[] prev) { if (depth > maxDepth) { maxDepth = depth; maxNode = from; } for(int next: graph[from]) { if (visited[next]) continue; visited[next] = true; prev[next] = from; dist[next] = depth+1; dfs(next, depth+1, graph, visited, dist, prev); } } private List<Integer> roots = new ArrayList<>(); public List<Integer> findMinHeightTrees(int n, int[][] edges) { List<Integer>[] graph = new ArrayList[n]; for(int i=0; i<n; i++) graph[i] = new ArrayList<>(); for(int i=0; i<edges.length; i++) { graph[edges[i][0]].add(edges[i][1]); graph[edges[i][1]].add(edges[i][0]); } boolean[] visited = new boolean[n]; int[] dist1 = new int[n]; int[] prev1 = new int[n]; maxNode = 0; maxDepth = 0; visited[0] = true; dfs(0, 0, graph, visited, dist1, prev1); int node1 = maxNode; int[] dist2 = new int[n]; int[] prev2 = new int[n]; Arrays.fill(visited, false); maxNode = node1; maxDepth = 0; visited[node1] = true; dfs(node1, 0, graph, visited, dist2, prev2); int node2 = maxNode; int node = node2; for(int i=0; i<maxDepth/2; i++) node = prev2[node]; if ((maxDepth & 1) == 0) { roots.add(node); } else { roots.add(node); roots.add(prev2[node]); } return roots; }}
优化,利用prev特性避免使用visit数组:
public class Solution { private void find(int curr, int dist, int[] prev, List<Integer>[] graph, Node max) { if (dist >= max.dist) { max.dist = dist; max.id = curr; } for(int i=0; i<graph[curr].size(); i++) { int next = graph[curr].get(i); if (next == prev[curr]) continue; prev[next] = curr; find(next, dist+1, prev, graph, max); } } public List<Integer> findMinHeightTrees(int n, int[][] edges) { List<Integer>[] graph = new List[n]; for(int i=0; i<n; i++) graph[i] = new ArrayList<>(); for(int[] edge: edges) { graph[edge[0]].add(edge[1]); graph[edge[1]].add(edge[0]); } int[] prev = new int[n]; Arrays.fill(prev, -1); Node node1 = new Node(); find(0, 0, prev, graph, node1); Arrays.fill(prev, -1); Node node2 = new Node(); find(node1.id, 0, prev, graph, node2); List<Integer> roots = new ArrayList<>(); int id = node2.id; for(int i=0; i<node2.dist/2; i++) id = prev[id]; roots.add(id); if (node2.dist % 2 == 1) roots.add(prev[id]); return roots; }}class Node { int id = -1; int dist = Integer.MIN_VALUE;}
方法二:动态规划。
public class Solution { private int[] length; private int[][] height; private List<Integer>[] graph; private void dfs(int parent, int current) { for(int next: graph[current]) { if (next == parent) continue; dfs(current, next); int h = height[next][0] + 1; if (h > height[current][0]) { height[current][1] = height[current][0]; height[current][0] = h; } else if (h > height[current][1]) { height[current][1] = h; } } } private int min; private void dfs(int parent, int current, int longest) { length[current] = Math.max(longest, height[current][0]); if (length[current] < min) min = length[current]; for(int next: graph[current]) { if (next == parent) continue; int nl = Math.max(longest+1, height[next][0]+1==height[current][0]? height[current][1]+1 : height[current][0]+1); dfs(current, next, nl); } } public List<Integer> findMinHeightTrees(int n, int[][] edges) { List<Integer> roots = new ArrayList<>(); if (n==0) return roots; if (n<=2) { for(int i=0; i<n; i++) roots.add(i); return roots; } min = n; length = new int[n]; height = new int[n][2]; graph = new List[n]; for(int i=0; i<n; i++) graph[i] = new ArrayList<>(); for(int i=0; i<edges.length; i++) { graph[edges[i][0]].add(edges[i][1]); graph[edges[i][1]].add(edges[i][0]); } dfs(-1, 0); dfs(-1, 0, 0); for(int i=0; i<n; i++) { if (length[i] == min) roots.add(i); } return roots; }}
优化,将参数定义为高度和半径,含义更清晰:
public class Solution { private int min = Integer.MAX_VALUE; private int[] radius; private int[][] height; private List<Integer>[] graph; private void calcHeight(int prev, int curr) { for(int i=0; i<graph[curr].size(); i++) { int next = graph[curr].get(i); if (next == prev) continue; calcHeight(curr, next); int h = height[next][0] + 1; if (h > height[curr][0]) { height[curr][1] = height[curr][0]; height[curr][0] = h; } else if (h > height[curr][1]) { height[curr][1] = h; } } } private void calcRadius(int prev, int curr, int sum) { radius[curr] = Math.max(sum, height[curr][0]); if (radius[curr] < min) min = radius[curr]; for(int i=0; i<graph[curr].size(); i++) { int next = graph[curr].get(i); if (next == prev) continue; int nextSum; if (height[next][0]+1 == height[curr][0]) nextSum = Math.max(sum, height[curr][1]) + 1; else nextSum = Math.max(sum, height[curr][0]) + 1; calcRadius(curr, next, nextSum); } } public List<Integer> findMinHeightTrees(int n, int[][] edges) { radius = new int[n]; height = new int[n][2]; graph = new List[n]; for(int i=0; i<n; i++) graph[i] = new ArrayList<>(); for(int[] edge: edges) { graph[edge[0]].add(edge[1]); graph[edge[1]].add(edge[0]); } calcHeight(-1, 0); calcRadius(-1, 0, 0); List<Integer> roots = new ArrayList<>(); for(int i=0; i<n; i++) { if (radius[i] == min) roots.add(i); } return roots; }}
啰嗦一点的方法:
public class Solution { private int[] radius; private int[][] height; private int[][] htnode; private List<Integer>[] graph; private void find(int prev, int node) { for(int next: graph[node]) { if (next == prev) continue; find(node, next); if (height[next][0] + 1 > height[node][0]) { height[node][0] = height[next][0] + 1; htnode[node][0] = next; } } for(int next: graph[node]) { if (next == prev) continue; if (next == htnode[node][0]) continue; if (height[next][0] + 1 > height[node][1]) { height[node][1] = height[next][0] + 1; htnode[node][1] = next; } } } private void find(int prev, int node, int sum) { radius[node] = Math.max(sum, height[node][0]); for(int next: graph[node]) { if (next == prev) continue; if (next == htnode[node][0]) { find(node, next, Math.max(sum+1, height[node][1]+1)); } else { find(node, next, Math.max(sum+1, height[node][0]+1)); } } } public List<Integer> findMinHeightTrees(int n, int[][] edges) { radius = new int[n]; height = new int[n][2]; htnode = new int[n][2]; graph = new List[n]; for(int i=0; i<n; i++) graph[i] = new ArrayList<>(); for(int[] edge: edges) { graph[edge[0]].add(edge[1]); graph[edge[1]].add(edge[0]); } find(-1, 0); find(-1, 0, 0); int min = Integer.MAX_VALUE; for(int r: radius) min = Math.min(min, r); List<Integer> roots = new ArrayList<>(); for(int i=0; i<radius.length; i++) { if (radius[i] == min) roots.add(i); } return roots; }}
参考文章:https://leetcode.com/discuss/72739/two-o-n-solutions
- LeetCode 310. Minimum Height Trees(最小高度树)
- 310. Minimum Height Trees(最小高度树)
- 第四周:310. Minimum Height Trees(最小高度树)
- leetcode 310. Minimum Height Trees 最小高度树 + DFS深度优先遍历 + 拓扑排序
- LeetCode 310. Minimum Height Trees(超时)
- Leetcode 310. Minimum Height Trees
- [leetcode] 310. Minimum Height Trees
- 310. Minimum Height Trees LeetCode
- leetcode 310. Minimum Height Trees
- LeetCode *** 310. Minimum Height Trees
- 【LeetCode】310. Minimum Height Trees
- [leetcode] 310.Minimum Height Trees
- leetcode-310. Minimum Height Trees
- [leetcode] 310. Minimum Height Trees
- 【LeetCode】310. Minimum Height Trees
- LeetCode 310. Minimum Height Trees
- Leetcode 310. Minimum Height Trees
- [LeetCode]310. Minimum Height Trees
- ❝ SLES11升级OpenSSL到openssl-1.0.1h ❞
- AIDL
- Java递归实例
- linux软件管理
- Q:suse 11.1上安装R 3.2.2
- LeetCode 310. Minimum Height Trees(最小高度树)
- C# 矩形面积 0002
- hive和hbase表数据同步
- Rule of Three
- 正则表达式引擎实现体会
- 扩展欧几里得算法
- hbase集群安装(1)-ssh安装及配置
- Android的Touch系统简介(一)
- hbase集群安装(2)-ubuntu下jdk安装