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 = 4edges = [[1, 0], [1, 2], [1, 3]]

        0
|
1
/ \
2 3

return [1]

Example 2:

Given n = 6edges = [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]]

     0  1  2
\ | /
3
|
4
|
5

return [3, 4]

Hint:

  1. 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.

问题:给定一个拥有树性质的无向图,图的每一个节点都可以视为一棵树的根节点。在所有可能的树中,找出高度最小的树,并返回他们的树根。

思路一 :

求最小高度的树,实际上是一个求最优解题目。求最优解,我首先想到的是动态规划(DP)思路。这个题目也确实满足 DP 的两个主要性质:overlapping substructure & optimal substructure 。思路比较直观:

  1. 视某个节点为树根节点,求这棵树的树高。
  2. 对所有节点进行上面的求解,得到 n 个树高,其中高度最小的树的树根即为原题目的解。

对于1,如何求解节点 A 为树根的树高?

假设已知 A 的所有相邻节点分别为树根的各个子树的树高,那么 A根的树高等于  已知的各个子树树高中的最大值 加一。方程式表达如下,即状态转换方程:

height(A) = max(height(A.next0), height(A.next2),... height(A.nextk)) + 1

对于2, 存在大量重复计算。可以借助表格,将已计算的树分支高度保存下来后续使用,避免重复计算。将当前节点以及其中一个相邻节点组合分支方向,求得该分支高度后存入 map<string, int> direc_height 中,其中 direc 有这两个节点组成作为 key ,height 表示高度。

若不使用表格优化,时间复杂度为 O(V*E)。使用表格,相当于进行了剪枝,会快不少。跑 LeetCode 的大集合 V = 1000, E =2000 ,测试耗时是 820ms,可惜没能过 submit 要求。

 private:

     // dirct consists of two node cur_next, height means the height of the subtree which souce node is the current node and walk forward on the cur_next direction
map<string, int> direc_height; public: /**
* calulate the height of a tree which parent node is p and current node is node
*
*/
int getHeight(gnode* node, gnode* p){
int h = ;
for (int i = ; i < node->neighbours.size(); i++){
gnode* tmpn = node->neighbours[i];
if (tmpn == p){
continue;
} int tmph;
string str = to_string(node->val) + "_" + to_string(tmpn->val);
if(direc_height.count(str) != ){
tmph = direc_height[str];
}else{
tmph = getHeight(tmpn, node);
direc_height[str] = tmph;
} h = max(h, tmph);
} return h + ;
} vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) { map<int, gnode*> val_node;
for(int i = ; i < n ; i++){
gnode* node = new gnode(i);
val_node[i] = node;
} for (int i = ; i < edges.size(); i++){
pair<int, int> pp = edges[i];
val_node[pp.first]->neighbours.push_back(val_node[pp.second]);
val_node[pp.second]->neighbours.push_back(val_node[pp.first]);
} int minh = INT_MAX; map<int, int> node_height; map<int, gnode*>::iterator m_iter;
for(m_iter = val_node.begin(); m_iter != val_node.end(); m_iter++){
int h = getHeight(m_iter->second, NULL);
node_height[m_iter->first] = h;
minh = min(minh, h);
} vector<int> res;
map<int, int>::iterator mii_iter;
for(mii_iter = node_height.begin(); mii_iter != node_height.end(); mii_iter++){
if(mii_iter->second == minh){
res.push_back(mii_iter->first);
}
} return res;
}

思路二 :

除了 DP 方案,没有想到其他思路,在网上借鉴了其他了的想法,理解后实现通过。

这个思路实际上是一个 BFS 思路。和常见的从根节点进行 BFS 不同,这里从叶子节点开始进行 BFS。

所有入度(即相连边数)为 1 的节点即是叶子节点。找高度最小的节点,即找离所有叶子节点最远的节点,也即找最中心的节点。

找最中心的节点的思路很简单:

  • 每次去掉当前图的所有叶子节点,重复此操作直到只剩下最后的根。

根据这个思路可以回答题目中的 [ hint : How many MHTs can a graph have at most? ],只能有一个或者两个最小高度树树根。证明省略。

 class TNode{
public:
int val;
unordered_set<TNode*> neighbours;
TNode(int val){
this->val = val;
}
}; vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
map<int, TNode*> val_node; for (int i = ; i < n ; i++){
TNode* tmp = new TNode(i);
val_node[i] = tmp;
} for (int i = ; i < edges.size(); i++){
pair<int, int> pp = edges[i];
val_node[pp.first]->neighbours.insert(val_node[pp.second]);
val_node[pp.second]->neighbours.insert(val_node[pp.first]);
} map<int, TNode*>::iterator m_iter; while(val_node.size() > ){ // obtain all leaves in current graph;
list<TNode*> listg;
for ( m_iter = val_node.begin(); m_iter != val_node.end(); m_iter++){
if(m_iter->second->neighbours.size() == ){
listg.push_back(m_iter->second);
}
} // remove all leaves
list<TNode*>::iterator l_iter;
for(l_iter = listg.begin(); l_iter != listg.end(); l_iter++){
TNode* p = (*(*l_iter)->neighbours.begin());
p->neighbours.erase(*l_iter);
(*l_iter)->neighbours.erase(p); val_node.erase((*l_iter)->val);
}
} vector<int> res;
for ( m_iter = val_node.begin(); m_iter != val_node.end(); m_iter++){
res.push_back(m_iter->first); } return res;
}

参考资料:

C++ Solution. O(n)-Time, O(n)-Space, LeetCode OJ

[LeetCode] 310. Minimum Height Trees 解题思路的更多相关文章

  1. 【LeetCode】310. Minimum Height Trees 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 BFS 相似题目 参考资料 日期 题目地址:http ...

  2. [LeetCode] 310. Minimum Height Trees 最小高度树

    For a undirected graph with tree characteristics, we can choose any node as the root. The result gra ...

  3. leetcode@ [310] Minimum Height Trees

    For a undirected graph with tree characteristics, we can choose any node as the root. The result gra ...

  4. [LeetCode] 310. Minimum Height Trees_Medium tag: BFS

    For a undirected graph with tree characteristics, we can choose any node as the root. The result gra ...

  5. 310. Minimum Height Trees

    For a undirected graph with tree characteristics, we can choose any node as the root. The result gra ...

  6. 310. Minimum Height Trees -- 找出无向图中以哪些节点为根,树的深度最小

    For a undirected graph with tree characteristics, we can choose any node as the root. The result gra ...

  7. [LeetCode] 76. Minimum Window Substring 解题思路

    Given a string S and a string T, find the minimum window in S which will contain all the characters ...

  8. [LeetCode] Minimum Height Trees 最小高度树

    For a undirected graph with tree characteristics, we can choose any node as the root. The result gra ...

  9. LeetCode Minimum Height Trees

    原题链接在这里:https://leetcode.com/problems/minimum-height-trees/ 题目: For a undirected graph with tree cha ...

随机推荐

  1. 使用ssh对服务器进行登录

    一.什么是SSH? 简单说,SSH是一种网络协议,用于计算机之间的加密登录. 如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码也不会 ...

  2. Linux开发工具之Makefile(下)

    二.Makefile(下) 01.make常用内嵌函数 函数调用   $(function arguments) $(wildcard PATTERN)   当前目录下匹配模式的文件   例如:src ...

  3. post 封装Map 发送请求

    package com.j1.weixin.util; import java.io.IOException; import java.util.Map; import java.util.Set; ...

  4. C#解leetcode:119. Pascal's Triangle II

    题目是: Given an index k, return the kth row of the Pascal's triangle. For example, given k = 3,Return  ...

  5. ajax提交富文本,内容被截断,解决方法及思路

    问题描述: 使用百度的UEditor富文本插件用于前端富文本编辑,后端使用jsp,提交普通文本没有问题,后来发现在提交某些指定文本时,数据查回的数据出现不完整现象:第一件事就是想到“垃圾编辑器”

  6. JavaScript实现弹框

    提起JS弹框,我首先想到的是Alert,然后想到的还是Alert,最后我竟然就只知道Alert.然后面试就死在这个Alert上了.恼火. 根据网上各位大神的总结,我整理了一下,也顺便学习了一下. 一. ...

  7. Xcode快捷键 (本人总结常用的)

    以下分类显示最常用的快捷键: 1. 文件 CMD + N: 新文件 CMD + SHIFT + N:     新项目 CMD + O: 打开 CMD + S: 保存 CMD + SHIFT + S: ...

  8. poi大数据将excel2007导入数据库

    package com.jeeframe.cms.updata.service.impl; import java.io.IOException; import java.io.InputStream ...

  9. 【FLYabroad 】微软内部代码检查工具 (Microsoft Source Analysis for C#)[转]

    SourceAnalysis (StyleCop)的终极目标是让所有人都能写出优雅和一致的代码,因此这些代码具有很高的可读性. 早就听说了微软内部的静态代码检查和代码强制格式美化工具 StyleCop ...

  10. C#制作ActiveX控件及部署升级(摘自网络)

    使用C#开发ActiveX控件 控件开发.制作CAB包.签名.部署 ActiveX控件以前也叫做OLE控件,它是微软IE支持的一种软件组件或对象,可以将其插入到Web页面中,实现在浏览器端执行动态程序 ...