Given an undirected graph which has a tree characteristics represented using an adjacency list adj[][], we can choose any vertex as the root of the tree. Find all the vertices that, when chosen as the root, result in the minimum possible height of the tree.
Note: The height of a rooted tree is defined as the maximum number of edges on the path from the root to any leaf node.
[Naive Approach] By exploring all node as Root - O(V^2) Time and O(V) Space
The idea is to explore each node one by one as the root. For every node, we treat it as the root and find the height of the tree starting from that node to its farthest leaf node. After calculating heights for all nodes, we store the nodes with the minimum height in the result.
C++
//Driver Code Starts#include<iostream>#include<vector>#include<algorithm>usingnamespacestd;//Driver Code Ends// Performing DFS and find height from current nodeintfindHeight(intnode,intparent,vector<vector<int>>&adj){intheight=0;for(intneighbor:adj[node]){if(neighbor!=parent){height=max(height,1+findHeight(neighbor,node,adj));}}returnheight;}// Find all possible roots with minimum heightvector<int>findMinHeight(vector<vector<int>>&adj){intV=adj.size();vector<int>heights(V);// Try each node as root and find the heightfor(inti=0;i<V;i++){heights[i]=findHeight(i,-1,adj);}// Find the minimum height among all rootsintminHeight=*min_element(heights.begin(),heights.end());// Collect all roots giving minimum heightvector<int>result;for(inti=0;i<V;i++){if(heights[i]==minHeight)result.push_back(i);}returnresult;}//Driver Code Startsintmain(){// Given adjacency listvector<vector<int>>adj={{2},{2},{0,1,3},{2,4},{3}};vector<int>result=findMinHeight(adj);for(intr:result)cout<<r<<" ";cout<<endl;return0;}//Driver Code Ends
Java
//Driver Code Startsimportjava.util.ArrayList;importjava.util.Collections;classGFG{//Driver Code Ends// Performing DFS and find height from current nodestaticintfindHeight(intnode,intparent,ArrayList<ArrayList<Integer>>adj){intheight=0;for(intneighbor:adj.get(node)){if(neighbor!=parent){height=Math.max(height,1+findHeight(neighbor,node,adj));}}returnheight;}// Find all possible roots with minimum heightstaticArrayList<Integer>findMinHeight(ArrayList<ArrayList<Integer>>adj){intV=adj.size();ArrayList<Integer>heights=newArrayList<>(Collections.nCopies(V,0));// Try each node as root and find the heightfor(inti=0;i<V;i++){heights.set(i,findHeight(i,-1,adj));}// Find the minimum height among all rootsintminHeight=Collections.min(heights);// Collect all roots giving minimum heightArrayList<Integer>result=newArrayList<>();for(inti=0;i<V;i++){if(heights.get(i)==minHeight)result.add(i);}returnresult;}//Driver Code Starts// Function to add an undirected edgestaticvoidaddEdge(ArrayList<ArrayList<Integer>>adj,intu,intv){adj.get(u).add(v);adj.get(v).add(u);}publicstaticvoidmain(String[]args){// Given adjacency listintV=5;ArrayList<ArrayList<Integer>>adj=newArrayList<>();for(inti=0;i<V;i++)adj.add(newArrayList<>());addEdge(adj,0,2);addEdge(adj,1,2);addEdge(adj,2,3);addEdge(adj,3,4);ArrayList<Integer>result=findMinHeight(adj);for(intr:result)System.out.print(r+" ");System.out.println();}}//Driver Code Ends
Python
# Performing DFS and find height from current nodedeffindHeight(node,parent,adj):height=0forneighborinadj[node]:ifneighbor!=parent:height=max(height,1+findHeight(neighbor,node,adj))returnheight# Find all possible roots with minimum heightdeffindMinHeight(adj):V=len(adj)heights=[0]*V# Try each node as root and find the heightforiinrange(V):heights[i]=findHeight(i,-1,adj)# Find the minimum height among all rootsminHeight=min(heights)# Collect all roots giving minimum heightresult=[]foriinrange(V):ifheights[i]==minHeight:result.append(i)returnresult#Driver Code Startsif__name__=="__main__":adj=[[2],[2],[0,1,3],[2,4],[3]]result=findMinHeight(adj)forrinresult:print(r,end=" ")print()#Driver Code Ends
C#
//Driver Code StartsusingSystem;usingSystem.Collections.Generic;classGFG{//Driver Code Ends// Performing DFS and find height from current nodestaticintfindHeight(intnode,intparent,List<List<int>>adj){intheight=0;foreach(intneighborinadj[node]){if(neighbor!=parent){height=Math.Max(height,1+findHeight(neighbor,node,adj));}}returnheight;}// Find all possible roots with minimum heightstaticList<int>findMinHeight(List<List<int>>adj){intV=adj.Count;List<int>heights=newList<int>(newint[V]);// Try each node as root and find the heightfor(inti=0;i<V;i++){heights[i]=findHeight(i,-1,adj);}// Find the minimum height among all rootsintminHeight=int.MaxValue;foreach(inthinheights)minHeight=Math.Min(minHeight,h);// Collect all roots giving minimum heightList<int>result=newList<int>();for(inti=0;i<V;i++){if(heights[i]==minHeight)result.Add(i);}returnresult;}//Driver Code Starts// Function to add an undirected edgestaticvoidaddEdge(List<List<int>>adj,intu,intv){adj[u].Add(v);adj[v].Add(u);}staticvoidMain(){// Given adjacency listintV=5;List<List<int>>adj=newList<List<int>>();for(inti=0;i<V;i++)adj.Add(newList<int>());addEdge(adj,0,2);addEdge(adj,1,2);addEdge(adj,2,3);addEdge(adj,3,4);List<int>result=findMinHeight(adj);foreach(intrinresult)Console.Write(r+" ");Console.WriteLine();}}//Driver Code Ends
JavaScript
// Performing DFS and find height from current nodefunctionfindHeight(node,parent,adj){letheight=0;for(letneighborofadj[node]){if(neighbor!==parent){height=Math.max(height,1+findHeight(neighbor,node,adj));}}returnheight;}// Find all possible roots with minimum heightfunctionfindMinHeight(adj){constV=adj.length;constheights=newArray(V).fill(0);// Try each node as root and find the heightfor(leti=0;i<V;i++){heights[i]=findHeight(i,-1,adj);}// Find the minimum height among all rootsconstminHeight=Math.min(...heights);// Collect all roots giving minimum heightconstresult=[];for(leti=0;i<V;i++){if(heights[i]===minHeight)result.push(i);}returnresult;}//Driver Code Starts// Given adjacency listconstadj=[[2],[2],[0,1,3],[2,4],[3]];constresult=findMinHeight(adj);console.log(result.join(" "));//Driver Code Ends
Output
2 3
[Expected Approach] Using Topological Sorting - O(V) Time and O(V) Space
Observation:
Consider a simple path:
If we take node 0 as root - height = 3
If we take node 1 as root - height = 2 (minimum height)
If we take node 2 as root - height = 2 (minimum height)
If we take node 3 as root - height = 3
So, node 1 and 2 (which lies in the middle) gives the minimum height. Similarly, in longer or more complex trees, the center or middle nodes always produce the minimum height.
Why the Center Works ?
The reason is simple: in a tree, every node is connected by exactly one path. If we keep moving inward by removing outermost leaves, we are getting closer to the middle of the longest path.Once all the leaves are removed, the last one or two remaining nodes must be the centers of the tree. These are the roots that minimize the height — because they are equally distant from all edges of the tree.
The idea is we use a topological sort–like approach. First, we identify all the leaf nodes(degree 1). We then remove these leaf nodes from the graph. As we remove each leaf, we decrease the degree of its connected neighbor nodes. After removal, if any of those neighbors become new leaves (their degree becomes 1), we mark them for the next round.We keep repeating this process level by level, trimming the tree from the outside in.
In the end, when only one or two nodes remain, those are the center nodes of the graph — the points that are equally close to all other nodes and give the minimum possible height when chosen as roots.
C++
//Driver Code Starts#include<iostream>#include<vector>#include<queue>usingnamespacestd;//Driver Code Endsvector<int>findMinHeight(vector<vector<int>>&adj){intV=adj.size();// Base case: if less than 2 nodesif(V<2){vector<int>centroids;for(inti=0;i<V;i++)centroids.push_back(i);returncentroids;}// Store degree of each nodevector<int>deg(V);for(inti=0;i<V;i++)deg[i]=adj[i].size();// Initialize the first layer of leavesqueue<int>leaves;for(inti=0;i<V;i++)if(deg[i]==1)leaves.push(i);intremNodes=V;// Trim the leaves level by level until reaching the centroidswhile(remNodes>2){intleafCount=leaves.size();remNodes-=leafCount;for(inti=0;i<leafCount;i++){intleaf=leaves.front();leaves.pop();for(intneighbor:adj[leaf]){deg[neighbor]--;if(deg[neighbor]==1)leaves.push(neighbor);}// mark as removeddeg[leaf]=0;}}// The remaining nodes are the centroidsvector<int>result;while(!leaves.empty()){result.push_back(leaves.front());leaves.pop();}returnresult;}//Driver Code Startsintmain(){// Given adjacency listvector<vector<int>>adj={{2},{2},{0,1,3},{2,4},{3}};vector<int>result=findMinHeight(adj);for(intr:result)cout<<r<<" ";cout<<endl;return0;}//Driver Code Ends
Java
//Driver Code Startsimportjava.util.ArrayList;classGFG{//Driver Code Ends// Find all possible roots with minimum heightstaticArrayList<Integer>findMinHeight(ArrayList<ArrayList<Integer>>adj){intV=adj.size();// Base case: if less than 2 nodesif(V<2){ArrayList<Integer>centroids=newArrayList<>();for(inti=0;i<V;i++)centroids.add(i);returncentroids;}// Store degree of each nodeint[]deg=newint[V];for(inti=0;i<V;i++)deg[i]=adj.get(i).size();// Initialize the first layer of leavesArrayList<Integer>leaves=newArrayList<>();for(inti=0;i<V;i++)if(deg[i]==1)leaves.add(i);intremNodes=V;// Trim the leaves level by level until reaching the centroidswhile(remNodes>2){intleafCount=leaves.size();remNodes-=leafCount;ArrayList<Integer>newLeaves=newArrayList<>();for(inti=0;i<leafCount;i++){intleaf=leaves.get(i);for(intneighbor:adj.get(leaf)){deg[neighbor]--;if(deg[neighbor]==1)newLeaves.add(neighbor);}// mark as removeddeg[leaf]=0;}leaves=newLeaves;}// The remaining nodes are the centroidsArrayList<Integer>result=newArrayList<>();for(intleaf:leaves)result.add(leaf);returnresult;}//Driver Code Starts// Add an undirected edgestaticvoidaddEdge(ArrayList<ArrayList<Integer>>adj,intu,intv){adj.get(u).add(v);adj.get(v).add(u);}publicstaticvoidmain(String[]args){intV=5;ArrayList<ArrayList<Integer>>adj=newArrayList<>();for(inti=0;i<V;i++)adj.add(newArrayList<>());// Add edgesaddEdge(adj,0,2);addEdge(adj,1,2);addEdge(adj,2,3);addEdge(adj,3,4);ArrayList<Integer>result=findMinHeight(adj);for(intr:result)System.out.print(r+" ");System.out.println();}}//Driver Code Ends
Python
#Driver Code Startsfromcollectionsimportdeque#Driver Code EndsdeffindMinHeight(adj):V=len(adj)# Base case: if less than 2 nodesifV<2:centroids=[]foriinrange(V):centroids.append(i)returncentroids# Store degree of each nodedeg=[len(adj[i])foriinrange(V)]# Initialize the first layer of leavesleaves=deque()foriinrange(V):ifdeg[i]==1:leaves.append(i)remNodes=V# Trim the leaves level by level until reaching the centroidswhileremNodes>2:leafCount=len(leaves)remNodes-=leafCountfor_inrange(leafCount):leaf=leaves.popleft()forneighborinadj[leaf]:deg[neighbor]-=1ifdeg[neighbor]==1:leaves.append(neighbor)deg[leaf]=0# mark as removed# The remaining nodes are the centroidsresult=[]whileleaves:result.append(leaves.popleft())returnresult#Driver Code Startsif__name__=="__main__":adj=[[2],[2],[0,1,3],[2,4],[3]]result=findMinHeight(adj)forrinresult:print(r,end=" ")print()#Driver Code Ends
C#
//Driver Code StartsusingSystem;usingSystem.Collections.Generic;classGFG{//Driver Code Ends// Find all possible roots with minimum heightstaticList<int>findMinHeight(List<List<int>>adj){intV=adj.Count;// Base case: if less than 2 nodesif(V<2){List<int>centroids=newList<int>();for(inti=0;i<V;i++)centroids.Add(i);returncentroids;}// Store degree of each nodeint[]deg=newint[V];for(inti=0;i<V;i++)deg[i]=adj[i].Count;// Initialize the first layer of leavesQueue<int>leaves=newQueue<int>();for(inti=0;i<V;i++)if(deg[i]==1)leaves.Enqueue(i);intremNodes=V;// Trim the leaves level by level until reaching the centroidswhile(remNodes>2){intleafCount=leaves.Count;remNodes-=leafCount;for(inti=0;i<leafCount;i++){intleaf=leaves.Dequeue();foreach(intneighborinadj[leaf]){deg[neighbor]--;if(deg[neighbor]==1)leaves.Enqueue(neighbor);}// mark as removeddeg[leaf]=0;}}// The remaining nodes are the centroidsList<int>result=newList<int>();while(leaves.Count>0)result.Add(leaves.Dequeue());returnresult;}//Driver Code Starts// Add an undirected edgestaticvoidaddEdge(List<List<int>>adj,intu,intv){adj[u].Add(v);adj[v].Add(u);}staticvoidMain(){intV=5;List<List<int>>adj=newList<List<int>>();for(inti=0;i<V;i++)adj.Add(newList<int>());// Add edgesaddEdge(adj,0,2);addEdge(adj,1,2);addEdge(adj,2,3);addEdge(adj,3,4);List<int>result=findMinHeight(adj);foreach(intrinresult)Console.Write(r+" ");Console.WriteLine();}}//Driver Code Ends
JavaScript
functionfindMinHeight(adj){constV=adj.length;// Base case: if less than 2 nodesif(V<2){constcentroids=[];for(leti=0;i<V;i++)centroids.push(i);returncentroids;}// Store degree of each nodeconstdeg=newArray(V).fill(0);for(leti=0;i<V;i++)deg[i]=adj[i].length;// Initialize the first layer of leavesletleaves=[];for(leti=0;i<V;i++)if(deg[i]===1)leaves.push(i);letremNodes=V;// Trim the leaves level by level until reaching the centroidswhile(remNodes>2){constleafCount=leaves.length;remNodes-=leafCount;constnewLeaves=[];for(leti=0;i<leafCount;i++){constleaf=leaves[i];for(constneighborofadj[leaf]){deg[neighbor]--;if(deg[neighbor]===1)newLeaves.push(neighbor);}deg[leaf]=0;// mark as removed}leaves=newLeaves;}// The remaining nodes are the centroidsreturnleaves;}//Driver Code Starts// Driver Code// Given adjacency listconstadj=[[2],[2],[0,1,3],[2,4],[3]];constresult=findMinHeight(adj);for(constrofresult)process.stdout.write(r+" ");console.log();//Driver Code Ends