Home » Technical Interview Questions » Tree Interview Questions » Minimum Height Trees

Minimum Height Trees


Reading Time - 9 mins

In the Minimum Height Trees problem, we have given an undirected graph which is tree in nature (acyclic and fully connected graph). Find out those vertices (or vertex) in the graph that when taken as root, will give tree with minimum height.

Height of Tree: Height of the tree rooted at some vertex v is the number of edges between the v and the vertex that is farthest from v.

Example

Minimum Height Trees

vertices 1 and 2 can form roots with minimum height tree.

Minimum Height Trees

vertex 4 can form root with minimum height tree.Minimum Height Trees

vertices 2 and 1 can form roots with minimum height tree.

Types of solution

  1. Using the Diameter of the tree.
  2. BFS based traversal from leaf nodes.

Using the Diameter of the tree

Approach

We find the diameter of the tree, the mid-point of the diameter are minimum height roots. If the length of the diameter is even, the middle two vertices are minimum height roots and if the length is odd the only middle vertex is minimum height root.

Finding the diameter 
  1. Choose any random vertex (say vertex with 0 value) and find the vertex (say first ) that is at the largest distance from the vertex chosen. This can be done using BFS/DFS. If there are multiple such vertices that are farthest from the chosen vertex, then take any one of them.
  2. Now look for the vertex ( say second ) that is at the largest distance from first. This can be done using BFS/DFS. If there are multiple such vertices that are farthest from first, then take any one of them. Now, first and last so obtained from the ends of the diameter.
  3. Obtain all the elements along the diameter using BFS/DFS including first and last.

After you have obtained the diameter, simply return it’s mid-points.

Algorithm

  1. Choose any random vertex (say 0).
  2. Perform BFS from 0 and look for the vertex farthest from it, say first.
  3. Perform BFS from first and look for the vertex farthest from it, say second.
  4. first and second form ends of the diameter.
  5. Again, perform BFS from first and track all the vertices falling along the diameter towards second, this is done by storing parent (predecessor during BFS) of each element along the path.
  6. return the middle elements(or element) of the diameter.

Minimum Height TreesMinimum Height Trees

Implementation

C++ Program
#include <iostream>
#include <bits/stdc++.h>
using namespace std;

/* function to add edge between nodes u and v */
void addEdge(vector <int> adj[],int u,int v)
{
    adj[u].push_back(v);
    adj[v].push_back(u);
}

/* function to perform BFS from a source vertex
and return vertex at largest distance from source */ 
int BFS(int s,vector <int> adj[],int v)
{
    /* define vectors to store visited status
    and distance from source vertex */
    vector <bool> vis(v,0);
    vector <int> dis(v,-1);
    queue <int> q;
    
    /* distance of source to itself is 0 */
    dis[s] = 0;
    q.push(s);
    
    /* begin BFS */
    while(!q.empty())
    {
        int top = q.front();
        q.pop();
        
        /* mark current largest as visited */
        vis[top] = 1;
        
        for(auto i : adj[top])
        {
            if(!vis[i])
            {
                /* mark neighbors of current largest as visited */
                vis[i] = 1;
                /* update distance of neighbors from current node */
                dis[i] = dis[top] + 1;
                q.push(i);
            }
        }
    }
    
    /* to store vertex that is at largest distance from source */
    int maxVertex;
    /* to store largest distance value */
    int maxDistance = INT_MIN;
    
    /* find vertex with largest distance from source */
    for(int i = 0;i < v;i++)
    {
        if(dis[i] > maxDistance)
        {
            maxVertex = i;
            maxDistance = dis[i];
        }
    }
    
    return maxVertex;
}
/* function that return nodes that form root with minimum height */
vector <int> rootMinHeight(vector <int> adj[],int v)
{
    /* take any vertex and find vertex at largest distance from it 
    store it in first */
    int first = BFS(0,adj,v);
    /* find the vertex at largest distance from first
    store it in last */
    int last = BFS(first,adj,v);
    
    /* first and last form diameter of the tree and
    minimum height vertex/vertices lie at the centre
    of diameter */
    
    /* diameter = largest path in a tree */
    
    /* peform BFS from first */
    
    vector <bool> vis(v,0);
    /* par store parent of each vertex during BFS traversal 
    this is used to track the path between first and last (diameter)*/
    vector <int> par(v,-1);
    
    queue <int> q;
    q.push(first);
    
    /* BFS */
    while(!q.empty())
    {
        int top = q.front();
        q.pop();
        
        vis[top] = 1;
        for(auto i : adj[top])
        {
            if(!vis[i])
            {
                vis[i] = 1;
                par[i] = top;
                q.push(i);
            }
        }
    }
    
    /* vector  to store the diameter of the given tree */
    vector <int> largestPath;
    
    /* begin traversal along the diameter starting 
    from last node towards first node */
    while(last != -1)
    {
        largestPath.push_back(last);
        last = par[last];
    }
    
    /* result vector to store mid elements of the 
    diameter, these elements are roots(or root) that form
    minimum height trees */
    vector <int> result;
    int size = largestPath.size();
    if(size % 2 == 0)
    {
        result.push_back(largestPath[(size-1)/2]);
        result.push_back(largestPath[size/2]);
    }
    else
    result.push_back(largestPath[size/2]);
    
    return result;
}

/* main function to implement above function */
int main() 
{
    int v = 10;
    
    vector <int> adj[v];
    
    /* construct the tree */
    addEdge(adj,0,1);
    addEdge(adj,1,2);
    addEdge(adj,2,4);
    addEdge(adj,4,5);
    addEdge(adj,2,9);
    addEdge(adj,2,3);
    addEdge(adj,1,6);
    addEdge(adj,6,7);
    addEdge(adj,6,8);
    
    /* obtain the vertex, that as a root form minimum height tree */
    vector <int> result = rootMinHeight(adj,v);
    
    /* root for minimum height tree lie at mid of the diameter */
    cout<<"Roots for minimum height tree are : ";
    for(auto i : result)
    cout<<i<<" ";
    
    
  return 0;
}
Roots for minimum height tree are : 1 2
Java Program
import java.util.*;
import java.io.*;

class tutorialCup
{
    /* function to add edge between nodes u and v */
    static void addEdge(ArrayList <ArrayList<Integer>> adj,int u,int v)
    {
        adj.get(u).add(v);
        adj.get(v).add(u);
    }
    /* function to perform BFS from a source vertex
    and return vertex at largest distance from source */ 
    static int BFS(int s,ArrayList<ArrayList<Integer>> adj,int v)
    {
        /* define vectors to store visited status
        and distance from source vertex */
        ArrayList <Boolean> vis = new ArrayList<>();
        ArrayList <Integer> dis = new ArrayList<>();
        Queue <Integer> q = new LinkedList<>();
        
        for(int i=0;i<v;i++)
        {
            vis.add(false);
            dis.add(-1);
        }
        
        /* distance of source to itself is 0 */
        dis.set(s,0);
        q.add(s);
        /* begin BFS */
        while(!q.isEmpty())
        {
            int top = q.poll();
            
            /* mark current largest as visited */
            vis.set(top,true);
            
            Iterator itr = adj.get(top).iterator();
            while(itr.hasNext())
            {
                int i = (Integer)itr.next();
                if(!vis.get(i))
                {
                    q.add(i);
                    dis.set(i,dis.get(top)+1);
                    vis.set(i,true);
                }
            }
        }
        
        /* to store vertex that is at largest distance from source */
        int maxVertex = 0;
        /* to store largest distance value */
        int maxDistance = Integer.MIN_VALUE;
        
        /* find vertex with largest distance from source */
        for(int i = 0;i < v;i++)
        {
            if(dis.get(i) > maxDistance)
            {
                maxVertex = i;
                maxDistance = dis.get(i);
            }
        }
        
        return maxVertex;
    }
    
    /* function that return nodes that form root with minimum height */
    static ArrayList <Integer> rootMinHeight(ArrayList <ArrayList<Integer>> adj,int v)
    {
        /* take any vertex and find vertex at largest distance from it 
        store it in first */
        int first = BFS(0,adj,v);
        /* find the vertex at largest distance from first
        store it in last */
        int last = BFS(first,adj,v);
        
        /* first and last form diameter of the tree and
        minimum height vertex/vertices lie at the centre
        of diameter */
        
        /* diameter = largest path in a tree */
        
        /* peform BFS from first */
        
        ArrayList <Boolean> vis = new ArrayList<>();
        /* par stores parent of each vertex during BFS traversal 
        this is used to track the path between first and last (diameter)*/
        ArrayList <Integer> par = new ArrayList<>();
        
        for(int i=0;i<v;i++)
        {
            vis.add(false);
            par.add(-1);
        }
        
        Queue <Integer> q = new LinkedList<>();
        q.add(first);
        
        /* BFS */
        while(!q.isEmpty())
        {
            int top = q.poll();
            
            vis.set(top,true);
            Iterator itr = adj.get(top).iterator();
            while(itr.hasNext())
            {
                int i = (Integer)itr.next();
                if(!vis.get(i))
                {
                    vis.set(i,true);
                    par.set(i,top);
                    q.add(i);
                }
            }
        }
        
        /* vector  to store the diameter of the given tree */
        ArrayList <Integer> largestPath = new ArrayList<>();
        
        /* begin traversal along the diameter starting 
        from last node towards first node */
        while(last != -1)
        {
            largestPath.add(last);
            last = par.get(last);
        }
        
        /* result vector to store mid elements of the 
        diameter, these elements are roots(or root) that form
        minimum height trees */
        ArrayList <Integer> result = new ArrayList<>();
        int size = largestPath.size();
        if(size % 2 == 0)
        {
            result.add(largestPath.get((size-1)/2));
            result.add(largestPath.get(size/2));
        }
        else
        result.add(largestPath.get(size/2));
    
        return result;
    }
    
    public static void main (String[] args) 
    {
        int v = 10;
    
        ArrayList <ArrayList<Integer>> adj = new ArrayList<ArrayList<Integer>>();
        
        for(int i=0;i<v;i++)
        adj.add(new ArrayList<Integer>());
        
        /* construct the tree */
        addEdge(adj,0,1);
        addEdge(adj,1,2);
        addEdge(adj,2,4);
        addEdge(adj,4,5);
        addEdge(adj,2,9);
        addEdge(adj,2,3);
        addEdge(adj,1,6);
        addEdge(adj,6,7);
        addEdge(adj,6,8);
        
        /* obtain the vertex, that as a root form minimum height tree */
        ArrayList <Integer> result = rootMinHeight(adj,v);
        
        /* root for minimum height tree lie at mid of the diameter */
        System.out.println("Roots for minimum height tree are : ");
        
        Iterator itr = result.iterator();
        while(itr.hasNext())
            System.out.print(itr.next()+" ");
    }
}
Roots for minimum height tree are : 1 2

Complexity Analysis

  1. Time Complexity : T(n) = O(V+E), but for trees E = V-1, therefore T(n) = O(2V – 1) = O(V).
  2. Space Complexity : A(n) = O(V).
READ  Binary Tree to Binary Search Tree Conversion

Using the Diameter of the tree

Approach

It is to be understood that a tree can only have 1 or 2 vertexes that form root nodes with minimum height. In this approach we perform BFS/DFS traversal from leaf nodes ( nodes that have degree = 1), keep deleting the leaves, and move on to its neighbors. We do this iteratively until only 1 or 2 vertices are left to be deleted. These remaining vertices are the vertices that form root nodes with minimum height.

Degree of a vertex: the degree of a vertex is the number of other vertices it is directly connected to through an undirected edge.

Algorithm

  1. Create an array that stores the degree of each vertex of the graph.
  2. Create a queue to perform BFS traversal.
  3. Identify the leaf vertices (vertices with degree = 1) and push them into the queue.
  4. Delete these leaves from the graph (mark them as visited) and traverse to their immediate neighbors (and also decrease their degrees by 1 , as they are disconnected with the leaf nodes) using BFS traversal.
  5. Perform steps 3 and 4 iteratively until only less than 3 vertices are left in the queue.
  6. These vertices form root nodes with a minimum height of the tree, Store these vertices (or vertex) in an array and return the array.

Minimum Height TreesMinimum Height Trees  

Implementation

C++ Program
#include <iostream>
#include <bits/stdc++.h>
using namespace std;

/* function to add edge between nodes u and v */
void addEdge(vector <int> adj[],int u,int v)
{
    adj[u].push_back(v);
    adj[v].push_back(u);
}

/* function that return nodes that form root with minimum height */
vector <int> rootMinHeight(vector <int> adj[],int v)
{
    /* vector that stores degree of each tree vertex */
    vector <int> degree;
    
    queue <int> q;
    for(int i=0;i<v;i++)
    {
        degree.push_back(adj[i].size());
        /* push leaf vertex (with degree 1) into the queue */
        if(adj[i].size() == 1)
        q.push(i);
    }
    
    /* begin BFS starting from leaf vertices (and deleting them) 
    until only 2 or less vertices are left to 
    be traversed. These vertices left unvisited
    form roots with minimum height tree */
  while (v > 2)
  {
    for (int i = 0; i < q.size(); i++)
    {
      int top = q.front();
      q.pop();
      v--;

      /* for neighbors of the leaf, decrease their degrees
      and if those vertices turn out to be  leaf vertices
      push them into the queue */
      for (auto j : adj[top])
      {
        degree[j]--;
        if (degree[j] == 1)
          q.push(j);
      }
    }
  }

  /* the only vertices (or vertex) remaining in the queue
  are the ones that form minimum height tree, store them
  into a vector and return the vector */
  vector<int> result;
  while (!q.empty())
  {
    result.push_back(q.front());
    q.pop();
  }
  
  return result;
}

/* main function to implement above function */
int main() 
{
    int v = 10;
    
    vector <int> adj[v];
    
    /* construct the tree */
    addEdge(adj,0,1);
    addEdge(adj,1,2);
    addEdge(adj,2,4);
    addEdge(adj,4,5);
    addEdge(adj,2,9);
    addEdge(adj,2,3);
    addEdge(adj,1,6);
    addEdge(adj,6,7);
    addEdge(adj,6,8);
    
    /* obtain the vertex, that as a root form minimum height tree */
    vector <int> res = rootMinHeight(adj,v);
    
    /* root for minimum height tree lie at mid of the diameter */
    cout<<"Roots for minimum height tree are : ";
    for(auto i : res)
    cout<<i<<" ";
    
    
  return 0;
}
Output
Roots for minimum height tree are : 2 1
Java Program
import java.util.*;
import java.io.*;

class tutorialCup
{
    /* function to add edge between nodes u and v */
    static void addEdge(ArrayList <ArrayList<Integer>> adj,int u,int v)
    {
        adj.get(u).add(v);
        adj.get(v).add(u);
    }
    
    /* function that return nodes that form root with minimum height */
    static ArrayList <Integer> rootMinHeight(ArrayList<ArrayList<Integer>> adj, int v)
    {
        /* vector that stores degree of each tree vertex */
        ArrayList <Integer> degree = new ArrayList<>();
        Queue <Integer> q = new LinkedList<>();
        
        for(int i=0;i<v;i++)
        {
            degree.add(adj.get(i).size());
            /* push leaf vertex (with degree 1) into the queue */
            if(adj.get(i).size() == 1)
            q.add(i);
        }
        
        /* begin BFS starting from leaf vertices (and deleting them) 
        until only 2 or less vertices are left to 
        be traversed. These vertices left unvisited
        form roots with minimum height tree */
    	while (v > 2)
    	{
    		for (int i = 0; i < q.size(); i++)
    		{
    			int top = q.poll();
    			v--;
    
    			/* for neighbors of the leaf, decrease their degrees
    			and if those vertices turn out to be  leaf vertices
    			push them into the queue */
    			Iterator itr = adj.get(top).iterator();
    			
    			while (itr.hasNext())
    			{
    			    int j = (Integer)itr.next();
    				degree.set(j,degree.get(j)-1);
    				if (degree.get(j) == 1)
    					q.add(j);
    			}
    		}
    	}
    
    	/* the only vertices (or vertex) remaining in the queue
    	are the ones that form minimum height tree, store them
    	into a vector and return the vector */
    	ArrayList <Integer> result = new ArrayList<>();
    	while (!q.isEmpty())
    		result.add(q.poll());
    	
    	return result;
    }

    
    public static void main (String[] args) 
    {
        int v = 10;
    
        ArrayList <ArrayList<Integer>> adj = new ArrayList<ArrayList<Integer>>();
        
        for(int i=0;i<v;i++)
        adj.add(new ArrayList<Integer>());
        
        /* construct the tree */
        addEdge(adj,0,1);
        addEdge(adj,1,2);
        addEdge(adj,2,4);
        addEdge(adj,4,5);
        addEdge(adj,2,9);
        addEdge(adj,2,3);
        addEdge(adj,1,6);
        addEdge(adj,6,7);
        addEdge(adj,6,8);
        
        /* obtain the vertex, that as a root form minimum height tree */
        ArrayList <Integer> res = rootMinHeight(adj,v);
        
        /* root for minimum height tree lie at mid of the diameter */
        System.out.println("Roots for minimum height tree are : ");
        
        Iterator itr = res.iterator();
        while(itr.hasNext())
            System.out.print(itr.next()+" ");
    }
}
Roots for minimum height tree are : 2 1

Complexity Analysis

  1. Time Complexity : T(n) = O(V+E), but for trees E = V-1, therefore T(n) = O(2V – 1) = O(V).
  2. Space Complexity : A(n) = O(V).
READ  Maximum Binary Tree

References

Array Interview Questions
Graph Interview Questions
LinkedList Interview Questions
String Interview Questions
Tree Interview Questions