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]
題意:
給一個數字n,代表了無向圖的節點總數。然後給出該圖中所有的邊。找出以某個節點爲根節點,使得樹的高度最短。
思路:
最簡單的暴力的方式就是嘗試以每個節點作爲根節點,然後使用廣度優遍歷的方法去遍歷這個樹的高度。不過這樣的話時間複雜度就變成了O(n^2)。
換一個思路。我們知道在樹中有葉子節點跟非葉子節點兩種。葉子節點的度是1,即只有一個點與葉子節點相鄰
(也或者只有一個節點的話就沒有相鄰的節點)。中間節點的度都>=2。
另一個知識就是去找一根繩子的長度,我們可以讓兩隻螞蟻從兩端開始爬行,每次爬一步,若干步後它們相遇或者只差一步就說明找到了繩子的長度了。
結合上面的知識,我們使用這樣的思路,讓螞蟻從各個葉子往中間爬,每次爬一步之後,丟棄上一個節點,
並且判斷此時哪些成爲了葉子節點,然後繼續爬,直到最後兩個螞蟻相遇或者差一步就是最長的一個距離了。
這兩個螞蟻的位置就是根的位置,這個樹最少要有這麼高。
public List<Integer> findMinHeightTrees(int n, int[][] edges) {
List<Integer> list=new ArrayList<Integer>();
if(n<=0)return list;
else if(edges.length<=0){
for (int i=0;i<n;i++)
list.add(i);
return list;
}
Map<Integer, ArrayList<Integer>> graph = new HashMap<Integer,ArrayList<Integer>>();
for(int i=0;i<n;i++) graph.put(i, new ArrayList<Integer>());
int[] neighbors = new int[n];
for(int[] edge :edges){//建立鄰接表
neighbors[edge[0]]++;
neighbors[edge[1]]++;
graph.get(edge[0]).add(edge[1]);
graph.get(edge[1]).add(edge[0]);
}
for(int i=0;i<n;i++)
if(graph.get(i).size()==1)list.add(i);
while(n>2){
List<Integer> newList=new ArrayList<Integer>();
for(int l :list){
--n;
for(int nb :graph.get(l)){
if(--neighbors[nb]==1)newList.add(nb);
}
}
list=newList;
}
return list;
}