310. Minimum Height Trees
来源:互联网 发布:c语言读取jpg图片 编辑:程序博客网 时间:2024/06/07 10:48
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]
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.
思路:又遇上了最痛苦的topological sort,赶紧补一下,http://blog.csdn.net/dm_vincent/article/details/7714519
其实还是比较简单的,就想着 “学某门课要先修某门课” 这个实际的例子,把indegree为0的先拿出来,也就是不需要任何先修课的课程可以先学,然后更新其他节点的indegree,因为已经修了一门了嘛,说不定可以修其他以此为基础的课程呢!
拓扑排序有2中实现方式:
(1)BFS(就是上面描述的)
(2)DFS (就是Coursera上algorithm课程老师描述的)
类似的题目:
https://leetcode.com/problems/course-schedule/?tab=Description
https://leetcode.com/problems/course-schedule-ii/?tab=Description(只记录degree计数即可)
这里当做无向图来对待:
import java.util.ArrayList;import java.util.Collections;import java.util.HashSet;import java.util.List;/* * 找到最长的那条path,中间的1个或者2个就是要找的 * 参考拓扑排序的BFS实现 * 如果有1条最长的path,那不断减掉degree为1的,最后剩下的就是 * 如果有2条最长的path,那他们必然相交于中点,如果不是,就必然可以找到更长的path,相交于中点的话,不断减掉degree为1的仍然是可行的 */public class Solution { public List<Integer> findMinHeightTrees(int n, int[][] edges) { if(n == 1)return Collections.singletonList(0); // 构建degree集合,因为要最后的结果,所以不能简单用一个数组对degree计数 List<HashSet<Integer>> degree = new ArrayList<HashSet<Integer>>(); for(int i=0; i<n; i++)degree.add(new HashSet<Integer>()); for(int[] edge : edges) { degree.get(edge[0]).add(edge[1]); degree.get(edge[1]).add(edge[0]); } // 不断删除degree为0的节点,再更新剩下的节点的degree,所以用一个数组保存当前degree为0的节点 List<Integer> leaves = new ArrayList<Integer>(); for(int i=0; i<n; i++) if(degree.get(i).size() == 1) leaves.add(i); // 一直往中点收缩,剩下个1就是1个,剩下2个就是2个 while(n > 2) { n = n - leaves.size(); List<Integer> newLeaves = new ArrayList<Integer>(); // 更新degree for(int leaf : leaves) { for(int j : degree.get(leaf)) { degree.get(j).remove(leaf); // 不可能出现degree为0, if(degree.get(j).size() == 1) newLeaves.add(j); } } leaves = newLeaves; } return leaves; }}
二刷:
看了一下第一次刷写的博客,感觉完全不一样,还是要多刷,不然都找不到题目的感觉
这次刷因为有一刷的概念,直接想到了从两边收索找中点的思路,写了以下:
package l310;import java.util.ArrayList;import java.util.HashSet;import java.util.List;import java.util.Set;/* * last case TLE */public class ArrayBFS { public List<Integer> findMinHeightTrees(int n, int[][] edges) { int[] degree = new int[n]; boolean[][] adj = new boolean[n][n]; for(int[] edge : edges) { degree[edge[0]] ++; degree[edge[1]] ++; adj[edge[0]][edge[1]] = true; adj[edge[1]][edge[0]] = true; } int cnt = 0; while(cnt < n-2) { Set<Integer> s = new HashSet<Integer>(); for(int i=0; i<n; i++) if(degree[i] == 1) { degree[i] = -1; s.add(i); } for(int i : s) for(int j=0; j<n; j++) if(adj[i][j])degree[j] --; cnt += s.size(); } List<Integer> ret = new ArrayList<Integer>(); for(int i=0; i<n; i++) if(degree[i] >= 0)ret.add(i); return ret; }}
猜想可能是因为是稀疏矩阵,用连接表可能会快一点
package l310;import java.util.ArrayList;import java.util.HashSet;import java.util.List;import java.util.Set;/* * last case TLE * so we use Map or List, notice we will always have 0 .. n-1, so we just use List * 还可以优化,求degree为1的节点的时候不需要遍历,只要每当有degree为1就加到一个Set里面(这好像也是拓扑排序的优化技巧) */public class Solution { public List<Integer> findMinHeightTrees(int n, int[][] edges) { int[] degree = new int[n]; List<List<Integer>> adj = new ArrayList<List<Integer>>(); for(int i=0; i<n; i++)adj.add(new ArrayList<Integer>()); for(int[] edge : edges) { degree[edge[0]] ++; degree[edge[1]] ++; adj.get(edge[0]).add(edge[1]); adj.get(edge[1]).add(edge[0]); } int cnt = 0; while(cnt < n-2) { Set<Integer> s = new HashSet<Integer>(); for(int i=0; i<n; i++) if(degree[i] == 1) { degree[i] = -1; s.add(i); } for(int i : s) for(int j : adj.get(i)) degree[j] --; cnt += s.size(); } List<Integer> ret = new ArrayList<Integer>(); for(int i=0; i<n; i++) if(degree[i] >= 0)ret.add(i); return ret; }}
看到有人说暴力也可以AC,就试了一下遍历每个节点当root求树高,再取最小值
package l310;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/* * TLE */public class BruteForce { public List<Integer> findMinHeightTrees(int n, int[][] edges) { Map<Integer, List<Integer>> m = new HashMap<Integer, List<Integer>>(); for(int[] edge : edges) { if(!m.containsKey(edge[0]))m.put(edge[0], new ArrayList<Integer>()); m.get(edge[0]).add(edge[1]); if(!m.containsKey(edge[1]))m.put(edge[1], new ArrayList<Integer>()); m.get(edge[1]).add(edge[0]); } int min = Integer.MAX_VALUE; List<Integer> ret = new ArrayList<Integer>(); ret.add(0); for(int root : m.keySet()) { boolean[] marked = new boolean[n]; marked[root] = true; int h = getHeight(m, root, marked); if(h < min){ min = h; ret.clear(); ret.add(root); } else if(h == min) { ret.add(root); } } return ret; }private int getHeight(Map<Integer, List<Integer>> m, int root, boolean[] marked) {int ret = 0;for(int next : m.get(root))if(!marked[next]) {marked[next] = true;ret = Math.max(ret, 1 + getHeight(m, next, marked));marked[next] = false;}return ret;}}
也试了一下Floyd算法
package l310;import java.util.ArrayList;import java.util.Arrays;import java.util.List;/* * Floyd * 某一行最大也不超过最大的一半就是可能的root */public class Floyd { public List<Integer> findMinHeightTrees(int n, int[][] edges) { // Floyd int[][] adj = new int[n][n]; for(int[] a : adj)Arrays.fill(a, Integer.MAX_VALUE); for(int[] edge : edges) { adj[edge[0]][edge[1]] = 1; adj[edge[1]][edge[0]] = 1; } for(int k=0; k<n; k++) for(int i=0; i<n; i++) for(int j=0; j<n; j++) if(adj[i][k]!=Integer.MAX_VALUE && adj[k][j]!=Integer.MAX_VALUE && i!=j && adj[i][k] + adj[k][j] < adj[i][j]) adj[i][j] = adj[i][k] + adj[k][j]; // int[] max = new int[n]; for(int i=0; i<n; i++) for(int j=0; j<n; j++) if(adj[i][j] != Integer.MAX_VALUE) max[i] = Math.max(max[i], adj[i][j]); int allMax = 0; for(int a : max) if(a != Integer.MAX_VALUE)allMax = Math.max(allMax, a); int validMax = (allMax+1)/2; List<Integer> ret = new ArrayList<Integer>(); for(int i=0; i<n; i++) if(max[i] <= validMax)ret.add(i); return ret;}}
但是这些暴力解答都没有AC
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- 310. Minimum Height Trees
- Git 常用功能总结
- 使用Oracle发送http请求
- 数据链路层中的LLC
- JVM工具介绍之JPS虚拟机进程状况工具
- 文章标题
- 310. Minimum Height Trees
- 算法训练 链表数据求和操作
- JVM学习1
- 蓝桥杯 —— 结点选择 —— 树状DP
- 星系炸弹
- vmware station中 UDEV 无法获取共享存储磁盘的UUID,症状: scsi_id -g -u -d /dev/sdb 无返回结果。
- java中synchronized关键字的认识&记录
- SpringMVC 注解
- 原生js显示隐藏div区域块