题目链接:
题目大意:
给定一个具有树的性质的无向图, 选择其中任意一个节点作为根节点即可生成一棵有根树, 所有不同的生成树中, 高度最小的那些便被称为 minimum height trees (MHTs), 现要求找出 给定无向图的 MHTs, 返回结果为 各MHT 的根节点(对应的 label) ;
格式说明:
给定的无向图共含有 n个节点, 各节点对应 0, 1, ..., n-1 的 label ;
输入为 n, 以及 无向边集(用 label 的对 表示边) edges ;
例如: 给定: n = 4, edges = [ [1, 0], [1, 2], [1, 3] ], 则输出应为: [1] ;
又例: 给定: n = 6, edges = [ [0, 3], [1, 3], [2, 3], [4, 3], [5, 4] ], 则输出应为: [3, 4] ;
( 注: 还是看原题链接里的 Example 比较好, 有 示意图 ... )
解题过程:
(1) 考虑 MHTs 的高度都是相同的, 且原无向图已经可以看作一棵树, 所以直观上便可以直接由外往内推进, 即, 逐步将 最外围的节点(叶子节点) 摘去(也即, 生成树的高度+1), 最终剩下的(或 最后才被摘去的) 节点便可以被选作根节点 ;
(2) 然后可以考虑用 degree 来表示 节点的相互关系, 即, 最外围的节点肯定是 degree = 1 的 ;
(3) 这样, 就只需要考虑 处理好节点与节点之间的关系(如: 摘去一个节点, 其相邻节点也会有所改变, 但这些改变本身显然不应该对其他节点产生影响), 以免错乱, 即可 ;
代码如下:
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
vector<int> degrees(n, 0);
vector< unordered_set<int> > adjs(n, unordered_set<int>() );
for (auto e : edges) {
auto nodeA = e.first;
auto nodeB = e.second;
degrees[nodeA]++;
degrees[nodeB]++;
adjs[nodeA].insert(nodeB);
adjs[nodeB].insert(nodeA);
}
vector<int> candidateLeafs;
unordered_set<int> candidateRoots;
for (size_t i = 0; i < n; i++) { candidateRoots.insert(i); }
do {
candidateLeafs.clear();
for (size_t i = 0; i < degrees.size(); i++) {
if (degrees[i] == 1) {
candidateLeafs.push_back(i);
candidateRoots.erase(i);
}
}
for (auto i : candidateLeafs) {
degrees[i]--;
for (auto n : adjs[i]) {
degrees[n]--;
adjs[n].erase(i);
}
}
} while (candidateRoots.size() > 0 && candidateLeafs.size() > 0);
if (candidateLeafs.size() > 0) { return candidateLeafs; }
vector<int> ret;
for (auto r : candidateRoots) { ret.push_back(r); }
return ret;
}
};
(*) 这里实现得颇冗长, 比如, 在这里, 对一个节点来说, degree 和 相邻节点是有关联的 ; 而且, 考虑到其本身就已经是一棵树, 所以也可以直接利用 树 的特性, 比如, 叶子节点被摘去后新的叶子节点必然只可能是其本来的相邻节点, 等等 ;
Runtime: 102 ms
题目链接:
题目大意:
给定一个具有树的性质的无向图, 选择其中任意一个节点作为根节点即可生成一棵有根树, 所有不同的生成树中, 高度最小的那些便被称为 minimum height trees (MHTs), 现要求找出 给定无向图的 MHTs, 返回结果为 各MHT 的根节点(对应的 label) ;
格式说明:
给定的无向图共含有 n个节点, 各节点对应 0, 1, ..., n-1 的 label ;
输入为 n, 以及 无向边集(用 label 的对 表示边) edges ;
例如: 给定: n = 4, edges = [ [1, 0], [1, 2], [1, 3] ], 则输出应为: [1] ;
又例: 给定: n = 6, edges = [ [0, 3], [1, 3], [2, 3], [4, 3], [5, 4] ], 则输出应为: [3, 4] ;
( 注: 还是看原题链接里的 Example 比较好, 有 示意图 ... )
解题过程:
(1) 考虑 MHTs 的高度都是相同的, 且原无向图已经可以看作一棵树, 所以直观上便可以直接由外往内推进, 即, 逐步将 最外围的节点(叶子节点) 摘去(也即, 生成树的高度+1), 最终剩下的(或 最后才被摘去的) 节点便可以被选作根节点 ;
(2) 然后可以考虑用 degree 来表示 节点的相互关系, 即, 最外围的节点肯定是 degree = 1 的 ;
(3) 这样, 就只需要考虑 处理好节点与节点之间的关系(如: 摘去一个节点, 其相邻节点也会有所改变, 但这些改变本身显然不应该对其他节点产生影响), 以免错乱, 即可 ;
代码如下:
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
vector<int> degrees(n, 0);
vector< unordered_set<int> > adjs(n, unordered_set<int>() );
for (auto e : edges) {
auto nodeA = e.first;
auto nodeB = e.second;
degrees[nodeA]++;
degrees[nodeB]++;
adjs[nodeA].insert(nodeB);
adjs[nodeB].insert(nodeA);
}
vector<int> candidateLeafs;
unordered_set<int> candidateRoots;
for (size_t i = 0; i < n; i++) { candidateRoots.insert(i); }
do {
candidateLeafs.clear();
for (size_t i = 0; i < degrees.size(); i++) {
if (degrees[i] == 1) {
candidateLeafs.push_back(i);
candidateRoots.erase(i);
}
}
for (auto i : candidateLeafs) {
degrees[i]--;
for (auto n : adjs[i]) {
degrees[n]--;
adjs[n].erase(i);
}
}
} while (candidateRoots.size() > 0 && candidateLeafs.size() > 0);
if (candidateLeafs.size() > 0) { return candidateLeafs; }
vector<int> ret;
for (auto r : candidateRoots) { ret.push_back(r); }
return ret;
}
};
(*) 这里实现得颇冗长, 比如, 在这里, 对一个节点来说, degree 和 相邻节点是有关联的 ; 而且, 考虑到其本身就已经是一棵树, 所以也可以直接利用 树 的特性, 比如, 叶子节点被摘去后新的叶子节点必然只可能是其本来的相邻节点, 等等 ;
Runtime: 102 ms