#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <map>
using namespace std;
/*
问题:
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]
Show Hint
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.
分析:此题实际上是给定无向图,确定其中一个结点作为根节点,使得该结点对应的树高度最小,返回
这样的根节点集合。看上去应该是图的遍历。如何评估高度:从选定的根节点到叶节点(后续没有孩子结点)
的高度。求这种高度感觉应该是深度优先遍历,一直遍历到当前的结点,
此时累加深度
如果当前结点没有访问过,继续遍历该结点的所有邻接结点
如果当前结点的所有邻接结点全部访问过,说明该结点为叶节点,统计高度并更新最大高度
如果已经访问过,说明当前是叶节点,得到根节点到叶节点的高度,并更新
最大高度。然后需要返回到上一层结点。难点在于如何回到上一层结点?等于是要回到父节点,最好的办法就是
设定双向指向的结点。这个不行。不对,其实不算是父节点,应该算是其连接结点
图的表示里面有邻接矩阵和邻接表。
邻接表:每个结点指向其所邻接的结点,这个可以。
不需要设计边。用点表示
vector< vector<int> >表示:
这样的话:需要遍历每一个结点做上述的处理,并记录<根节点,最大高度>这样的映射,从该映射中
选择最小高度的根节点集合作为最终结果。
输入:
2(结点个数) 1(边数)
0(边的一个顶点) 1(边的另一个顶点)
4 3
1 0
1 2
1 3
6 5
0 3
1 3
2 3
4 3
5 4
2 []
输出:
0 1
1
3 4
0 1
报错:
Input:1 []
Output:[]
Expected:[0]
也就是说如果没有边,虽然有1个结点,那么高度为0;没有边,要把所有结点算作结果集
果然超时。但是通过邻接表遍历图的时间复杂度是O(n),总的时间复杂度为O(n^2)。
能否记录每个结点到另一个结点的最长距离,这个问题转化为floyd问题,时间复杂度为O(n^3)
多源最短路径
关键:
1 参考:https://leetcode.com/problems/minimum-height-trees/?tab=Solutions 解法
采用不断删除叶子结点的方法来逼近根节点,则最后剩下1个结点或者两个结点都是可能的
结果值,
2 没有边,要把所有结点算作结果集
*/
class Solution {
public:
struct Node
{
unordered_set<int> _neighbours;//存储邻居结点,查询时间复杂度为O(1)
bool isLeaf() // 叶子结点就是度数为1的结点
{
return _neighbours.size() == 1 ;
}
};
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
vector<int> result;
if(n < 0)
{
return result;
}
//如果没有边,高度为0,所有结点都是结果集
if( edges.empty())
{
for(int i = 0 ; i < n ;i++)
{
result.push_back(i);
}
return result;
}
vector< Node > nodes(n);
int size = edges.size();
pair<int , int> edgePair;
//生成邻接表,每个结点,生成其邻接的结点
for(int i = 0 ; i < size ; i++)
{
edgePair = edges.at(i);
nodes.at(edgePair.first)._neighbours.insert(edgePair.second);
nodes.at(edgePair.second)._neighbours.insert(edgePair.first);
}
//寻找叶节点
vector<int> leafs;
for(int i = 0 ; i < n ; i++)
{
if(nodes.at(i).isLeaf())
{
leafs.push_back(i);
}
}
vector<int> newLeafs;
//不断删除叶节点(删除叶节点连接的结点中的该叶节点),直到最后找不到叶节点,就返回
while(true)
{
if(leafs.empty())
{
break;
}
size = leafs.size();
//遍历每个叶子结点
for(int i = 0 ; i < size ; i++)
{
int leafIndex = leafs.at(i);
unordered_set<int> neighs = nodes.at(leafIndex)._neighbours;
//删除其邻居中该叶子结点,如果删除后其邻居变成叶子结点,则加入到新的叶子结点集合中
for(unordered_set<int>::iterator it = neighs.begin() ; it != neighs.end() ; it++)
{
int neighValue = *it;
nodes.at( neighValue )._neighbours.erase( leafIndex );
if(nodes.at(neighValue).isLeaf())
{
newLeafs.push_back(neighValue);
}
}
}
//如果当前叶节点被删除后,后续没有叶节点,则这就是最短树对应的根节点集合
if(newLeafs.empty())
{
return leafs;
}
else
{
//清空叶节点
leafs.clear();
//交换结点
swap(newLeafs , leafs);
}
}
return result;
}
};
void print(vector<int>& result)
{
if(result.empty())
{
cout << "no result" << endl;
return;
}
int size = result.size();
for(int i = 0 ; i < size ; i++)
{
cout << result.at(i) << " " ;
}
cout << endl;
}
void process()
{
vector<pair<int, int> > edges;
int num;
int edgeNum;
Solution solution;
vector<int> result;
while(cin >> num >> edgeNum)
{
edges.clear();
for(int i = 0 ; i < edgeNum ; i++)
{
pair<int , int> resultPair;
cin >> resultPair.first >> resultPair.second;
edges.push_back(resultPair);
}
result = solution.findMinHeightTrees(num , edges);
print(result);
}
}
int main(int argc , char* argv[])
{
process();
getchar();
return 0;
}
/*
void dfs(vector< vector<int> >& nodes , unordered_map<int , bool>& visited ,
int node , int& maxHeight , int height)
{
//如果当前结点已经访问过,直接返回
//设置当前结点为已经访问
visited[node] = true;
vector<int> nextNodes = nodes.at(node);
//如果当前结点,没有邻居结点,则当前结点为叶节点,统计高度。
if(nextNodes.empty())
{
maxHeight = max(height , maxHeight);
return;
}
//对当前结点的所有邻居结点,进行遍历
int nextSize = nextNodes.size();
bool isAllVisited = true;
int nextNode;
for(int j = 0 ; j < nextSize ; j++)
{
nextNode = nextNodes.at(j);
//如果当前结点的邻居结点已经访问过,那么说明,无需遍历,
if(visited.find(nextNode) == visited.end())
{
isAllVisited = false;
//以该结点继续进行访问
dfs(nodes , visited , nextNode , maxHeight , height + 1);
}
}
//如果当前结点的所有邻居结点都已经访问过,说明当前结点为叶节点
if(isAllVisited)
{
maxHeight = max(height , maxHeight);
}
}
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
vector<int> result;
if(n < 0)
{
return result;
}
//如果没有边,高度为0,所有结点都是结果集
if( edges.empty())
{
for(int i = 0 ; i < n ;i++)
{
result.push_back(i);
}
return result;
}
vector< vector<int> > nodes( n , vector<int>());
int size = edges.size();
pair<int , int> edgePair;
//生成邻接表,每个结点,生成其邻接的结点
for(int i = 0 ; i < size ; i++)
{
edgePair = edges.at(i);
nodes.at(edgePair.first).push_back(edgePair.second);
nodes.at(edgePair.second).push_back(edgePair.first);
}
//接下来对每个结点尝试作为根节点,计算其最大高度
unordered_map<int , bool> visited;
map<int , int> rootToHeight;
int minHeight = INT_MAX;
for(int i = 0 ; i < n ; i++)
{
visited.clear();
int node = i;
int height = 0;
int maxHeight = INT_MIN;
dfs(nodes , visited , node , maxHeight , 0);
rootToHeight[node] = maxHeight;
minHeight = min(minHeight , maxHeight);
}
//寻找出最小的高度
for(map<int , int>::iterator it = rootToHeight.begin(); it != rootToHeight.end() ; it++)
{
if(minHeight == it->second)
{
result.push_back(it->first);
}
}
return result;
}
*/
leecode 解题总结:275. H-Index II
最新推荐文章于 2023-10-16 15:32:56 发布