生活随笔
收集整理的這篇文章主要介紹了
310. Minimum Height Trees
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
輸入:包含n個節(jié)點的無向圖。n:表示從0到n-1,n個節(jié)點。edges:int數(shù)組,是從一個節(jié)點到另外一個節(jié)點。但是沒有方向。
輸出:以哪些節(jié)點為根節(jié)點,具有最小高度的樹,返回這些根節(jié)點。
規(guī)則:一個樹的高度是指從根節(jié)點到葉子節(jié)點的最遠路徑。最小高度樹,是指所有樹中高度最小的樹。
分析:當只有一個節(jié)點的時候,只要返回節(jié)點0就可以。
當有兩個節(jié)點且相連的時候,哪個節(jié)點做根節(jié)點,樹的高度都相同。
當有3個節(jié)點的時候,node1和node3肯定不能為根節(jié)點,因為以node2為根,高度是1;而以node1或者node3高度為2。也就是說當有3個或者以上節(jié)點的時候,使用葉子節(jié)點做根節(jié)點的樹肯定不符合要求。假設(shè)葉子節(jié)點nodeA為根是高度最小樹,那么nodeA肯定有子節(jié)點還有其他節(jié)點,否則一棵樹不能包含所有節(jié)點。那么以nodeA的子節(jié)點為根,高度減1,與假設(shè)不符合。有了這個結(jié)論:使用葉子節(jié)點做根節(jié)點的樹肯定不符合要求。(這個觀點的來源)我們就可以使用動態(tài)規(guī)劃的思路來不斷解決更小的問題。
例如上圖5個節(jié)點的圖,node4,node5不是根節(jié)點,那誰是呢?把node4,node5從圖中移除,只剩下node1,node2,node3,3個節(jié)點。
在這3個節(jié)點的圖中,node1,node3肯定不是根節(jié)點。將這兩個節(jié)點從圖中移除。就只有node2。也就是說node2是根節(jié)點。
在這個問題規(guī)模不斷變小的過程中,不斷去掉葉子節(jié)點。而這個操作不影響原有問題的答案。
public List<Integer> findMinHeightTrees(int n, int[][] edges) {Map<Integer,List<Integer>> graph = createGraph(edges,n);int[] inDegrees = new int[n];for(int[] edge : edges){inDegrees[edge[0]]++;inDegrees[edge[1]]++;}List<Integer> result = new ArrayList<Integer>();Queue<Integer> queue = new LinkedList<Integer>();for(int i=0;i<n;i++){if(inDegrees[i]==0){result.add(i);return result;}else if(inDegrees[i]==1){queue.offer(i);}}while(!queue.isEmpty()){result = new ArrayList<Integer>();int size = queue.size();for(int i=0;i<size;i++){int node = queue.poll();result.add(node);for(Integer toNode : graph.get(node)){inDegrees[toNode]--;if(inDegrees[toNode]==1){queue.offer(toNode);}}}}return result;}private Map<Integer,List<Integer>> createGraph(int[][] edges,int n){Map<Integer,List<Integer>> graph = new HashMap<Integer,List<Integer>>();for(int i=0;i<n;i++){graph.put(i,new ArrayList<Integer>());}for(int[] edge : edges){graph.get(edge[0]).add(edge[1]);graph.get(edge[1]).add(edge[0]);}return graph;}
分析2:分別以每個節(jié)點作為根節(jié)點計算樹的高度,在這個過程中比較記錄最小高度minHeight。遍歷之前的結(jié)果,等于minHeight的節(jié)點加入到結(jié)果集中。
在計算樹的高度的過程中,可以使用動態(tài)規(guī)劃的想法。假設(shè)已知 A 的所有相鄰節(jié)點分別為樹根的各個子樹的樹高,那么 A根的樹高等于 已知的各個子樹樹高中的最大值 加一。方程式表達如下,即狀態(tài)轉(zhuǎn)換方程:
height(A) = max(height(A.next0), height(A.next2),… height(A.nextk)) + 1(來源網(wǎng)址)
在計算過程中需要記錄各個子樹的高度,避免重復(fù)計算。緩存的key值是“當前節(jié)點->子節(jié)點”。
private Map<String,Integer> cache = new HashMap<String,Integer>();public List<Integer> findMinHeightTrees(int n, int[][] edges) {Map<Integer,List<Integer>> graph = createGraph(edges,n);int[] heights = new int[n];int minHeight = n;for(int i=0;i<n;i++){heights[i] = findHeight(graph,i,-1);minHeight = Math.min(minHeight,heights[i]);}List<Integer> result = new ArrayList<Integer>();for(int i=0;i<n;i++){if(heights[i]==minHeight){result.add(i);}}return result;}private int findHeight(Map<Integer,List<Integer>> graph,int root,int parent){int height = 0;for(Integer toNode : graph.get(root)){if(toNode==parent){continue;}String key = String.valueOf(root)+"->"+toNode;int tmp;if(cache.get(key)!=null){tmp = cache.get(key);}else{tmp = findHeight(graph,toNode,root);cache.put(key,tmp);}height = Math.max(height,tmp);}return height+1;}private Map<Integer,List<Integer>> createGraph(int[][] edges,int n){Map<Integer,List<Integer>> graph = new HashMap<Integer,List<Integer>>();for(int i=0;i<n;i++){graph.put(i,new ArrayList<Integer>());}for(int[] edge : edges){graph.get(edge[0]).add(edge[1]);graph.get(edge[1]).add(edge[0]);}return graph;}
代碼
總結(jié)
以上是生活随笔為你收集整理的310. Minimum Height Trees的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。