您的位置:首页 > 其它

310. Minimum Height Trees Add to List

2017-03-19 20:02 351 查看

LeetCode

题目地址:https://leetcode.com/problems/minimum-height-trees/#/description

思考过程:

题目要求是给一个具有树的属性的无向图,即每个点仅被另一条边连在一起,也就是说对于n个节点的图,只有n-1条边。题目目的是要找到其中一个节点作为根节点,能使得整个树的高度最小,这样的树叫做Minimum Height Tree(MHT)。

于是我一开始的想法很简单,(1)先根据输入构造边的一个map,(2)然后对从第0~n-1节点,计算一次深度,(3)最后根据深度的大小来返回MHT的根节点。但是这么做会在n=1000左右的时候超时,时间复杂度应该是O(n2),因为一共有n个点,每个点计算以它为根的深度,通过BFS来计算,复杂度是O(V+2E),因为是无向图每条边最多需要判断两次,每个点遍历一次,而V=n,E=n-1,复杂度即O(n),这样的过程有n次

然后参考了一下solution,只看了一下人家的思路,然后自己理解后写,思路大概是这样的,每次找到只有一条边连着的节点,剔除它,并剔除所有和他相连的边,最后剩下一个点或者两个点(一起连着,都是MHT的根节点),对于这个的时间复杂度就是O(V+E),因为对于每个点只访问一次,并且删除,同时对于每个边删除一次,由于V=n,E=n-1,所以O(n)

最后我的代码和答案的代码的对比,最主要的区别就是存储的时候,我用的是map,而答案用的是vector。这里我用map的原因是,每次检查到与该节点连接的边个数只有1的时候,需要把该节点删除,而map删除比vector快。但是答案的思路应该是每个节点只有一次机会,边数会变成1(变成是一个过程,从2然后erase一条边之后变成1),而之前边数是1的点不需要删除,因为下次再到它的时候(一定会再到它,因为无向图边是双向的),它的边数从1变成0,不会被考虑进去,也即相当于删除了,而在这里他节省了一些时间,所以我的算法和它的应该在常数项中会有点区别,毕竟对于unordered_map这种哈希map的删除时间应该是O(1)的,那么每次计算,我的复杂度会多O(n),但是总共的复杂度仍然是O(n)

代码

这是最开始自己的思路,超时

class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
vector<int> v;
int min = INT_MAX;
//construct m
for (vector<pair<int,int>>::iterator it = edges.begin(), end = edges.end(); it != end; it++) {
int one = it->first, two = it->second;
m[one].push_back(two);
m[two].push_back(one);
}
bool visit
;
for (int i = 0; i < n; i++) {
memset(visit,0,sizeof(visit));
int dep = depthWithNode(i,visit);
//cout << "i: " << i << " dep: " << dep << endl;
if (dep < min) {
v.clear();
v.push_back(i);
min = dep;
} else if (dep == min)
v.push_back(i);
}
return v;
}
//calculate depth with root node k
int depthWithNode(int k, bool* visit) {
//initial
clearCur();
clearNext();
cur.push(k);
visit[k] = true;
int height = 0;

while (!cur.empty()) {
height++;
while (!cur.empty()) {
int tmp = cur.front();
cur.pop();
for (int i = 0; i < m[tmp].size(); i++) {
if (!visit[m[tmp][i]]) {
next.push(m[tmp][i]);
visit[m[tmp][i]] = true;
}
}
}
cur = next;
clearNext();
}
return height;
}
void clearCur() {
while (!cur.empty())
cur.pop();
}
void clearNext() {
while (!next.empty())
next.pop();
}
private:
map<int,vector<int>> m;
queue<int> cur;
queue<int> next;
};


这是后来参考的思路,自己实现的,大概用时116ms

class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
vector<int> v(1,0);
//construct m
for (vector<pair<int,int>>::iterator it = edges.begin(), end = edges.end(); it != end; it++) {
int one = it->first, two = it->second;
m[one].insert(two);
m[two].insert(one);
}
while(m.size()) {
v.clear();
if (m.size() == 1) {
v.push_back(m.begin()->first);
break;
}
for (unordered_map<int,set<int>>::iterator it = m.begin(), end = m.end(); it != end; it++) {
if (it->second.size() == 1)
v.push_back(it->first);
}
int leafSize = v.size();
for (int i = 0; i < leafSize; i++) {
for (set<int>::iterator it = m[v[i]].begin(), end = m[v[i]].end(); it != end; it++) {
m[*it].erase(v[i]);
}
m.erase(v[i]);
}
}
sort(v.begin(),v.end());
return v;
}
private:
unordered_map<int,set<int>> m;
};


这是答案的代码,和我写的有一点点不同,不同在思路中写到了这里不重复,大概耗时43ms

class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
// Initialize the undirected graph
vector<set<int>> adj(n);
for (vector<pair<int,int>>::iterator it = edges.begin(), end = edges.end(); it != end; it++) {
adj[it->first].insert(it->second);
adj[it->second].insert(it->first);
}
// Corner case
vector<int> current;
if (n == 1) {
current.push_back(0);
return current;
}
// Create first leaf layer
for (int i = 0; i < adj.size(); ++i) {
if (adj[i].size() == 1) {
current.push_back(i);
}
}
// BFS the graph
while (true) {
vector<int> next;
for (int node : current) {
for (int neighbor : adj[node]) {
adj[neighbor].erase(node);
if (adj[neighbor].size() == 1) next.push_back(neighbor);
}
}
if (next.empty()) return current;
current = next;
}
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: