输入:包含n个节点的无向图。n:表示从0到n-1,n个节点。edges:int数组,是从一个节点到另外一个节点。但是没有方向。
输出:以哪些节点为根节点,具有最小高度的树,返回这些根节点。
规则:一个树的高度是指从根节点到叶子节点的最远路径。最小高度树,是指所有树中高度最小的树。
分析:当只有一个节点的时候,只要返回节点0就可以。

 当有两个节点且相连的时候,哪个节点做根节点,树的高度都相同。
 
 当有3个节点的时候,node1和node3肯定不能为根节点,因为以node2为根,高度是1;而以node1或者node3高度为2。也就是说当有3个或者以上节点的时候,使用叶子节点做根节点的树肯定不符合要求。假设叶子节点nodeA为根是高度最小树,那么nodeA肯定有子节点还有其他节点,否则一棵树不能包含所有节点。那么以nodeA的子节点为根,高度减1,与假设不符合。有了这个结论:使用叶子节点做根节点的树肯定不符合要求。(这个观点的来源)我们就可以使用动态规划的思路来不断解决更小的问题。
 
 例如上图5个节点的图,node4,node5不是根节点,那谁是呢?把node4,node5从图中移除,只剩下node1,node2,node3,3个节点。
 
 在这3个节点的图中,node1,node3肯定不是根节点。将这两个节点从图中移除。就只有node2。也就是说node2是根节点。
 在这个问题规模不断变小的过程中,不断去掉叶子节点。而这个操作不影响原有问题的答案。

public List<Integer> findMinHeightTrees(int n, int[][] edges) {Map<Integer,List<Integer>> graph = createGraph(edges,n);int[] inDegrees = new int[n];for(int[] edge : edges){inDegrees[edge[0]]++;inDegrees[edge[1]]++;}List<Integer> result = new ArrayList<Integer>();Queue<Integer> queue = new LinkedList<Integer>();for(int i=0;i<n;i++){if(inDegrees[i]==0){result.add(i);return result;}else if(inDegrees[i]==1){queue.offer(i);}}while(!queue.isEmpty()){result = new ArrayList<Integer>();int size = queue.size();for(int i=0;i<size;i++){int node = queue.poll();result.add(node);for(Integer toNode : graph.get(node)){inDegrees[toNode]--;if(inDegrees[toNode]==1){queue.offer(toNode);}}}}return result;}private Map<Integer,List<Integer>> createGraph(int[][] edges,int n){Map<Integer,List<Integer>> graph = new HashMap<Integer,List<Integer>>();for(int i=0;i<n;i++){graph.put(i,new ArrayList<Integer>());}for(int[] edge : edges){graph.get(edge[0]).add(edge[1]);graph.get(edge[1]).add(edge[0]);}return graph;}

分析2:分别以每个节点作为根节点计算树的高度,在这个过程中比较记录最小高度minHeight。遍历之前的结果,等于minHeight的节点加入到结果集中。
 在计算树的高度的过程中,可以使用动态规划的想法。假设已知 A 的所有相邻节点分别为树根的各个子树的树高,那么 A根的树高等于 已知的各个子树树高中的最大值 加一。方程式表达如下,即状态转换方程:
height(A) = max(height(A.next0), height(A.next2),… height(A.nextk)) + 1(来源网址)
在计算过程中需要记录各个子树的高度,避免重复计算。缓存的key值是“当前节点->子节点”。

private Map<String,Integer> cache = new HashMap<String,Integer>();public List<Integer> findMinHeightTrees(int n, int[][] edges) {Map<Integer,List<Integer>> graph = createGraph(edges,n);int[] heights = new int[n];int minHeight = n;for(int i=0;i<n;i++){heights[i] = findHeight(graph,i,-1);minHeight = Math.min(minHeight,heights[i]);}List<Integer> result = new ArrayList<Integer>();for(int i=0;i<n;i++){if(heights[i]==minHeight){result.add(i);}}return result;}private int findHeight(Map<Integer,List<Integer>> graph,int root,int parent){int height = 0;for(Integer toNode : graph.get(root)){if(toNode==parent){continue;}String key = String.valueOf(root)+"->"+toNode;int tmp;if(cache.get(key)!=null){tmp = cache.get(key);}else{tmp = findHeight(graph,toNode,root);cache.put(key,tmp);}height = Math.max(height,tmp);}return height+1;}private Map<Integer,List<Integer>> createGraph(int[][] edges,int n){Map<Integer,List<Integer>> graph = new HashMap<Integer,List<Integer>>();for(int i=0;i<n;i++){graph.put(i,new ArrayList<Integer>());}for(int[] edge : edges){graph.get(edge[0]).add(edge[1]);graph.get(edge[1]).add(edge[0]);}return graph;}

代码

310. Minimum Height Trees相关推荐

  1. leetcode 310. Minimum Height Trees | 310. 最小高度树(图的邻接矩阵DFS / 拓扑排序)

    题目 https://leetcode.com/problems/minimum-height-trees/ 题解 方法1:图的邻接矩阵 DFS(超时) 我一想,这不就是个图嘛,于是随手敲出一个 DF ...

  2. LeetCode 310. Minimum Height Trees

    文章目录 知识点 结果 菜鸡的DFS+记忆化 网友的BFS"剥洋葱" 实现 菜鸡的DFS+记忆化 代码 反思 网友的BFS"剥洋葱" 代码 反思 知识点 图的遍 ...

  3. 310. Minimum Height Trees 【Medium】 树

    题目:给出一个树,求出所有作为根节点时树的高度最小的节点 思路:用剪枝的办法,每次剪掉叶子节点,最终剩下一个或者两个节点时结束. 原理:一个节点的树的高度为该节点到最远的节点的距离,且此最远节点必为叶 ...

  4. leetcode310. Minimum Height Trees

    题目 For an undirected graph with tree characteristics, we can choose any node as the root. The result ...

  5. 树的最小高度 Minimum Height Trees

    2019独角兽企业重金招聘Python工程师标准>>> 问题: For a undirected graph with tree characteristics, we can ch ...

  6. LeetCode Minimum Height Trees(拓扑排序)

    问题:给出一个图,要求确定树的根,使得树的高度最小. 思路:先求出结点的度.然后将度数为1的入队列.在出队列时,将其邻接结点的度数减1,如果度数为1,则放入队列.直接剩余的结点数小于等于2 具体代码参 ...

  7. Lecture 16 Minimum Spanning Trees

  8. HDU 6691 Minimum Spanning Trees

    题目 题意: 对于一个n个点的图,每对点 u , v u,v u,v间有 p 0 p_0 p0​的几率没有边, p 1 p_1 p1​的几率有权值为1的边, p 2 p_2 p2​-边权 < = ...

  9. 继续过中等难度.0309

      .   8  String to Integer (atoi)    13.9% Medium   . 151 Reverse Words in a String      15.7% Mediu ...

最新文章

  1. Windows 10 install Pycharm 开发环境
  2. python创建进程的方法_python进程的状态、创建及使用方法详解
  3. mysql怎么删除唯一索引_mysql删除唯一索引
  4. 单继承-继承的概念和语法
  5. oracle unpivot 空值,sql – 处理UNPIVOT中的NULL值
  6. 【用jQuery来判断浏览器的类型】及【javascript获取用户ip地址】
  7. JVM——Java内存模型(JMM)
  8. 【数据结构】4.1图的创建及DFS深度遍历(不完善)
  9. apache的poi中设置Excel的单元格样式(HSSFCellStyle)和表格(HSSFSheet)
  10. 中英文对照 —— 图表等的可视化
  11. [Python] 生成迭代器 iter() 函数
  12. 页面置换算法(FIFOLRU)
  13. 【PC微信探秘】用易语言编写一个微信DLL注入器
  14. php怎么获取图片信息,PHP 获取图片信息exif
  15. java程序一图片为背景_利用Java处理图片,更换背景
  16. 【12306刷票必备!!!】12306订票助手----无所不能的谷歌浏览器chrome插件
  17. isInterrupted() interrupt() interrupted() 方法的简单解释
  18. openstreetmap-tile-server-ubuntu-16-04
  19. 【实例】使用 PHPExcel 读取excel 文件
  20. 史上最全的StarUML使用教程

热门文章

  1. JSTL之数字、日期格式化fmt:formatNumber/、fmt:formatDate/
  2. linux下memcache安装
  3. java mysql show status_Java 能不能执行mysql 中的show master status 命令
  4. 不同文件类型输出及ContentType表
  5. ubuntu mysql混合开发_mysql5.7主从同步 ubuntu
  6. web编程 模块1 html,PYcore python programming笔记C20 Web编程
  7. postgresql查询mysql库_postgresql 查看数据库,表,索引,表空间以及大小
  8. .net动态控件的使用(listview ,treeview,tabControl)
  9. 实现推拉ui样式_这推拉门隔断,我从没见过!直角设计同时划分3大功能区,太牛了...
  10. spring体系思维导图