LeetCode题解:Minimum Height Trees

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jining11/article/details/83184573

题目要求

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.

翻译一下就是,给定n个节点和若干条边,把它画成一棵树,并且返回这样所有的节点——当把它们看作是这棵树的根时,这棵树的深度是最小的。

果然会超时的邻接表暴力法

#include <iostream> 
#include <string>
#include <vector>
#include <queue>
using namespace std; 
class Solution {
public:
    //按层遍历获取树的高度
    int get_height(int root, vector <vector <int>> & map, int n) {
        int * flag = new int[n]();
        queue <int> Q;
        int label = 0;
        Q.push(root);
        while(!Q.empty()) {
            int count = Q.size();
            label++;
            for (; count > 0; count--) {
                int head = Q.front();
                flag[head] = 1;
                for (int p = 0; p < n; p++) {
                    if (map[head][p] && flag[p] == 0) {
                        Q.push(p);
                    }
                }
                Q.pop();
            }
        }
        delete[] flag;
        return label;
    }
    //返回最小的节点
    vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
        vector <vector <int>> map(n, vector<int>(n,0));
        for (auto & point: edges) {
        	map[point.first][point.second] = 1;
            map[point.second][point.first] = 1;
        }
        int min_height = n;
        int pre_height = 0;
        vector <int> height;
        for (int i = 0; i < n; i++) {
        	pre_height = get_height(i, map, n);
        	min_height = min_height > pre_height ? pre_height : min_height;
        	height.push_back(pre_height);
        }
        vector <int> result;
        for (int i = 0; i < n; i++) {
        	if (height[i] == min_height) {
        		result.push_back(i);
        	}
        }
        return result;
    }
};

int main() {
	Solution s;
	vector<pair<int, int>> edges;
	edges.push_back(pair<int, int>(0,3));
	edges.push_back(pair<int, int>(1,3));
	edges.push_back(pair<int, int>(2,3));
	edges.push_back(pair<int, int>(4,3));
	edges.push_back(pair<int, int>(5,4));
	vector<int> a = s.findMinHeightTrees(6, edges);
	for (auto i: a) {
		cout << i << endl;
	}
	return 0;
}

在节点数较小的情况下表现尚可,但是在最后几个例子里面还是超时了。如果一定要说这个算法有什么亮点的话,那大概就是我第一次用vector快捷地实现了一个二维数组,以及在BFS算法的基础上改进了一点点以实现分层遍历。

这回居然还没过的链表暴力法

有图为证

说真的,倒在最后一个样例上是最让人不爽的事情之一了。
——鲁迅

小改了一下算法,在图的最大度大于1的情况下,不再试图令度为1的节点也就是叶子结点成为根节点,顺带把邻接表换成了类似于链表的结构,但还是过不了最后的超大样例。难道是因为STL太慢了吗。。。

class Solution {
public:
    //按层遍历获取树的高度
    int get_height(int root, vector <vector <int>> & map, int n) {
        int * flag = new int[n]();
        queue <int> Q;
        int label = 0;
        Q.push(root);
        while(!Q.empty()) {
            int count = Q.size();
            label++;
            for (; count > 0; count--) {
                int head = Q.front();
                flag[head] = 1;
                for (auto & p : map[head]) {
                    if (flag[p] == 0) {
                        Q.push(p);
                        flag[p] = 1;
                    }
                }
                Q.pop();
            }
        }
        delete[] flag;
        return label;
    }
    //返回最小的节点
    vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
    	vector <int> result;
    	//所有节点都是叶子结点有且只有这一种情况 
    	if (n == 2) {
    		result.push_back(0);
    		result.push_back(1);
    		return result;
		}
        vector <vector <int>> map(n);
        for (auto & point: edges) {
        	map[point.first].push_back(point.second);
            map[point.second].push_back(point.first);
        }
        int min_height = n;
        int pre_height = 0;
        vector <int> height;
        for (int i = 0; i < n; i++) {
        	if (map[i].size() == 1) {
        		height.push_back(-1);
        		continue;
			}
        	pre_height = get_height(i, map, n);
        	min_height = min_height > pre_height ? pre_height : min_height;
        	height.push_back(pre_height);
        }
        for (int i = 0; i < n; i++) {
        	if (height[i] == min_height) {
        		result.push_back(i);
        	}
        }
        return result;
    }
};

解法三:从入海口回溯三江源

这是我黔驴技穷之后看到大佬的思路豁然开朗做出来的,能想出这个解法真的令人惊叹。这道题最关键的一点在于,最终解只有一个或者是两个相互指向的节点,因为当有三个长度相同的根时,就必然会形成一个环。因此我们需要做的,仅仅是从叶子节点往上,层层回溯,直到只剩下两个或一个节点。

要留意的一个重要情况是,可能会有叶子节点直接指向根节点,如果此时就把根节点加入队列,根节点就会被踢出去,为此,还需要实时标记各个节点的度(这里的度是与尚未加入队列的节点建立起来的连接的数目),仅仅把那些度为1的节点加入队列。

class Solution {
public:
    //返回最小的节点
    vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
    	vector <int> result;
        vector <vector <int>> map(n);
        //标记访问过的节点的总数 
        int visited = 0;
        //标记是否访问某个节点
		int * flag = new int[n](); 
        //标记各个节点的度数
		int * degrees = new int[n](); 
        for (auto & point: edges) {
        	map[point.first].push_back(point.second);
            map[point.second].push_back(point.first);
            degrees[point.first]++;
            degrees[point.second]++;
        }
        queue <int> Q;
        for (int i = 0; i < n; i++) {
            if (degrees[i] <= 1) {
                Q.push(i);
                flag[i] = 1;
                visited++;
            }
        }
        //第二种情况是有还没有访问到的节点,针对一个根节点两个叶子结点的情况 
        while(Q.size() > 2 || n > visited) {
            int count = Q.size();
            for (; count > 0; count--) {
                int head = Q.front();
                for (auto & p : map[head]) {
                    if (flag[p] == 1) {
                    	continue;
                    }
                    degrees[p]--;
                    if (degrees[p] == 1) {
                    	Q.push(p);
                    	flag[p] = 1;
                        visited++;
					}
                }
                Q.pop();
            }
        }
        while(!Q.empty()) {
            result.push_back(Q.front());
            Q.pop();
        }
        delete [] flag;
        delete [] degrees;
        return result;
    }
};

猜你喜欢

转载自blog.csdn.net/jining11/article/details/83184573