LeetCode:310. Minimum Height Trees(Week 5)
阿新 • • 發佈:2018-11-10
310. Minimum Height Trees
-
題目
-
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 from0
ton - 1
. You will be given the number n and a list of undirectededges
(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]
edges
.
-
Example 1 :
Input: n = 4, edges = [[1, 0], [1, 2], [1, 3]] 0 | 1 / \ 2 3 Output: [1]
-
Example 2 :
Input: n = 6, edges = [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]] 0 1 2 \ | / 3 | 4 | 5 Output: [3, 4]
-
Note:
- 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.”
- The height of a rooted tree is the number of edges on the longest downward path between the root and a leaf.
-
-
解題思路
-
解法1 - 暴力破解(
超時
,Failed
)- 步驟
- 以每個節點都為根,對每個節點使用BFS遍歷得到以該節點為根時樹的高度
- 比較各個節點時樹的高度,得到
Minimum Height Trees
的根節點
- 程式碼
class Solution { public: vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) { vector<int> v; int edgesArray[n][n]; int height[n]; for(int i = 0; i < n; ++i) { height[i] = getHeight(n, i, edges); } // 尋找最小高度樹的根節點 int min = n; for(int i = 0; i < n; ++i) { if(height[i] < min) { min = height[i]; v.clear(); v.push_back(i); } else if(height[i] == min) { v.push_back(i); } } return v; } // bfs遍歷 int getHeight(int n, int root, vector<pair<int, int> >& edges) { int h = 0; int visited[n] = {0}; visited[root] = 1; queue<int> q; q.push(root); int depth[n] = {0}; while(!q.empty()) { int tmp = q.front(); q.pop(); for(auto iter = edges.begin(); iter != edges.end(); iter++) { if((*iter).first == tmp || (*iter).second == tmp) { int newNode = (*iter).first + (*iter).second - tmp; if(!visited[newNode]) { depth[newNode] = depth[tmp] + 1; q.push(newNode); visited[newNode] = 1; } } } } int max = 0; for(int i = 0; i < n; ++i) { if(depth[i] > max) max = depth[i]; } return max; } };
- 複雜度 –
(
V
表示節點數量,E
表示邊的數量) - 結果果然超時了
- 改進與優化
- 可以利用map資料結構,來儲存每個節點對應其連線的節點所組成的一個對映
map<int, vector<int> >
,或者一個二維陣列 - 複雜度 –
(
V
表示節點數量,E
表示邊的數量) - 優化的程式碼
class Solution { public: vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) { vector<int> v; map<int, vector<int> > myMap; int height[n]; for(auto iter = edges.begin(); iter != edges.end(); iter++) { myMap[(*iter).first].push_back((*iter).second); myMap[(*iter).second].push_back((*iter).first); } for(int i = 0; i < n; ++i) { height[i] = getHeight(n, i, myMap); } // 尋找最小高度樹的根節點 int min = n; for(int i = 0; i < n; ++i) { if(height[i] < min) { min = height[i]; v.clear(); v.push_back(i); } else if(height[i] == min) { v.push_back(i); } } return v; } // bfs遍歷 int getHeight(int n, int root, map<int, vector<int> > myMap) { int h = 0; int visited[n] = {0}; visited[root] = 1; queue<int> q; q.push(root); int depth[n] = {0}; while(!q.empty()) { int tmp = q.front(); q.pop(); for(auto iter = myMap[tmp].begin(); iter != myMap[tmp].end(); iter++) { if(!visited[(*iter)]) { depth[(*iter)] = depth[tmp] + 1; q.push((*iter)); visited[(*iter)] = 1; } } } int max = 0; for(int i = 0; i < n; ++i) { if(depth[i] > max) max = depth[i]; } return max; } };
- 但是依舊超時
- 可以利用map資料結構,來儲存每個節點對應其連線的節點所組成的一個對映
- 步驟
-
思考提示:How many MHTs can a graph have at most?
- 每個樹最多有兩個MHTs。假如有三個或多個可以作為MHTs的根節點,根據樹的定義,每兩個節點都可以找到一條路徑連線起來,樹是一個強連通的圖,不存在簡單環,則至少一個一個或多個比其餘節點高,則大於三個MHTs不成立。
-
解法2 – 類剝洋蔥求解(
AC
)- 本方法學習自其他優秀解法
- 步驟
- 建立一個對映表,記錄每一個點與其直接相連的點
- 將樹的葉節點(度為1的節點)加入一個佇列中
- 假如當前佇列中儲存的節點數小於等於2,則退出迴圈。否則遍歷佇列中的每個節點。對每個節點,將其彈出佇列,同時將與其相連節點的集合中將該節點刪去,如果刪完該節點後此節點也變成一個葉節點(度數為1),那麼將這個節點加入佇列中。
- 時間複雜度 –
- 實現程式碼
class Solution { public: vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) { if(n == 1) return {0}; vector<int> ans; vector<set<int> > myVec(n); for(auto edge : edges) { myVec[edge.first].insert(edge.second); myVec[edge.second].insert(edge.first); } queue<int> q; for(int i = 0; i < n; ++i) if(myVec[i].size() == 1) q.push(i); while(n > 2) { int size = q.size(); n -= size; for(int i = 0; i < size; ++i) { int tmp = q.front(); q.pop(); for (auto it : myVec[tmp]) { myVec[it].erase(tmp); if (myVec[it].size() == 1) q.push(it); } } } while(!q.empty()) { ans.push_back(q.front()); q.pop(); } return ans; } };
-