Roots of a Tree Which Give Minimum Height

Last Updated : 16 Jan, 2026

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.

Example: 

Input: adj[][] = [[2], [2], [0, 1, 3], [2, 4], [3]]

roots_of_a_tree_which_give_minimum_height2-

Ouput: [2, 3]
Explanation: If we choose vertices 2 or 3 as the root, the resulting tree has the minimum possible height, which is 2.

file
Try It Yourself
redirect icon

[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>
using namespace std;
//Driver Code Ends


// Performing DFS and find height from current node
int findHeight(int node, int parent, vector<vector<int>> &adj) {
    int height = 0;
    for (int neighbor : adj[node]) {
        if (neighbor != parent) {
            height = max(height, 1 + findHeight(neighbor, node, adj));
        }
    }
    return height;
}

// Find all possible roots with minimum height
vector<int> findMinHeight(vector<vector<int>> &adj) {
    int V = adj.size();
    vector<int> heights(V);

    // Try each node as root and find the height
    for (int i = 0; i < V; i++) {
        heights[i] = findHeight(i, -1, adj);
    }

    // Find the minimum height among all roots
    int minHeight = *min_element(heights.begin(), heights.end());

    // Collect all roots giving minimum height
    vector<int> result;
    for (int i = 0; i < V; i++) {
        if (heights[i] == minHeight)
            result.push_back(i);
    }

    return result;
}


//Driver Code Starts
int main() {
    // Given adjacency list
    vector<vector<int>> adj = {{2}, {2}, {0, 1, 3}, {2, 4}, {3}};

    vector<int> result = findMinHeight(adj);

    for (int r : result) cout << r << " ";
    cout << endl;

    return 0;
}

//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;
import java.util.Collections;

class GFG {
//Driver Code Ends


    // Performing DFS and find height from current node
    static int findHeight(int node, int parent, ArrayList<ArrayList<Integer>> adj) {
        int height = 0;
        for (int neighbor : adj.get(node)) {
            if (neighbor != parent) {
                height = Math.max(height, 1 + findHeight(neighbor, node, adj));
            }
        }
        return height;
    }

    // Find all possible roots with minimum height
    static ArrayList<Integer> findMinHeight(ArrayList<ArrayList<Integer>> adj) {
        int V = adj.size();
        ArrayList<Integer> heights = new ArrayList<>(Collections.nCopies(V, 0));

        // Try each node as root and find the height
        for (int i = 0; i < V; i++) {
            heights.set(i, findHeight(i, -1, adj));
        }

        // Find the minimum height among all roots
        int minHeight = Collections.min(heights);

        // Collect all roots giving minimum height
        ArrayList<Integer> result = new ArrayList<>();
        for (int i = 0; i < V; i++) {
            if (heights.get(i) == minHeight)
                result.add(i);
        }

        return result;
    }
    

//Driver Code Starts
    // Function to add an undirected edge
    static void addEdge(ArrayList<ArrayList<Integer>> adj, int u, int v) {
        adj.get(u).add(v);
        adj.get(v).add(u);
    }
    public static void main(String[] args) {

        // Given adjacency list
        int V = 5;
        ArrayList<ArrayList<Integer>> adj = new ArrayList<>();
        for (int i = 0; i < V; i++)
            adj.add(new ArrayList<>());

        addEdge(adj, 0, 2);
        addEdge(adj, 1, 2);
        addEdge(adj, 2, 3);
        addEdge(adj, 3, 4);

        ArrayList<Integer> result = findMinHeight(adj);

        for (int r : result) System.out.print(r + " ");
        System.out.println();
    }
}

//Driver Code Ends
Python
# Performing DFS and find height from current node
def findHeight(node, parent, adj):
    height = 0
    for neighbor in adj[node]:
        if neighbor != parent:
            height = max(height, 1 + findHeight(neighbor, node, adj))
    return height

# Find all possible roots with minimum height
def findMinHeight(adj):
    V = len(adj)
    heights = [0] * V

    # Try each node as root and find the height
    for i in range(V):
        heights[i] = findHeight(i, -1, adj)

    # Find the minimum height among all roots
    minHeight = min(heights)

    # Collect all roots giving minimum height
    result = []
    for i in range(V):
        if heights[i] == minHeight:
            result.append(i)

    return result


#Driver Code Starts
if __name__ == "__main__":
    adj = [[2], [2], [0, 1, 3], [2, 4], [3]]
    
    result = findMinHeight(adj)
    
    for r in result:
        print(r, end=" ")
    print()

#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;

class GFG
{
//Driver Code Ends

    // Performing DFS and find height from current node
    static int findHeight(int node, int parent, List<List<int>> adj)
    {
        int height = 0;
        foreach (int neighbor in adj[node])
        {
            if (neighbor != parent)
            {
                height = Math.Max(height, 1 + findHeight(neighbor, node, adj));
            }
        }
        return height;
    }

    // Find all possible roots with minimum height
    static List<int> findMinHeight(List<List<int>> adj)
    {
        int V = adj.Count;
        List<int> heights = new List<int>(new int[V]);

        // Try each node as root and find the height
        for (int i = 0; i < V; i++)
        {
            heights[i] = findHeight(i, -1, adj);
        }

        // Find the minimum height among all roots
        int minHeight = int.MaxValue;
        foreach (int h in heights)
            minHeight = Math.Min(minHeight, h);

        // Collect all roots giving minimum height
        List<int> result = new List<int>();
        for (int i = 0; i < V; i++)
        {
            if (heights[i] == minHeight)
                result.Add(i);
        }

        return result;
    }
    

//Driver Code Starts
    // Function to add an undirected edge
    static void addEdge(List<List<int>> adj, int u, int v)
    {
        adj[u].Add(v);
        adj[v].Add(u);
    }

    static void Main()
    {
        // Given adjacency list
        int V = 5;
        List<List<int>> adj = new List<List<int>>();
        for (int i = 0; i < V; i++)
            adj.Add(new List<int>());

        addEdge(adj, 0, 2);
        addEdge(adj, 1, 2);
        addEdge(adj, 2, 3);
        addEdge(adj, 3, 4);

        List<int> result = findMinHeight(adj);

        foreach (int r in result)
            Console.Write(r + " ");
        Console.WriteLine();
    }
}

//Driver Code Ends
JavaScript
// Performing DFS and find height from current node
function findHeight(node, parent, adj) {
    let height = 0;
    for (let neighbor of adj[node]) {
        if (neighbor !== parent) {
            height = Math.max(height, 1 + findHeight(neighbor, node, adj));
        }
    }
    return height;
}

// Find all possible roots with minimum height
function findMinHeight(adj) {
    const V = adj.length;
    const heights = new Array(V).fill(0);

    // Try each node as root and find the height
    for (let i = 0; i < V; i++) {
        heights[i] = findHeight(i, -1, adj);
    }

    // Find the minimum height among all roots
    const minHeight = Math.min(...heights);

    // Collect all roots giving minimum height
    const result = [];
    for (let i = 0; i < V; i++) {
        if (heights[i] === minHeight)
            result.push(i);
    }

    return result;
}


//Driver Code Starts
// Given adjacency list
const adj = [[2], [2], [0, 1, 3], [2, 4], [3]];

const result = 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:

1345
  • 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>
using namespace std;
//Driver Code Ends


vector<int> findMinHeight(vector<vector<int>> &adj) {
    int V = adj.size();

    // Base case: if less than 2 nodes
    if (V < 2) {
        vector<int> centroids;
        for (int i = 0; i < V; i++)
            centroids.push_back(i);
        return centroids;
    }

    // Store degree of each node
    vector<int> deg(V);
    for (int i = 0; i < V; i++)
        deg[i] = adj[i].size();

    // Initialize the first layer of leaves
    queue<int> leaves;
    for (int i = 0; i < V; i++)
        if (deg[i] == 1)
            leaves.push(i);

    int remNodes = V;

    // Trim the leaves level by level until reaching the centroids
    while (remNodes > 2) {
        int leafCount = leaves.size();
        remNodes -= leafCount;

        for (int i = 0; i < leafCount; i++) {
            int leaf = leaves.front();
            leaves.pop();

            for (int neighbor : adj[leaf]) {
                deg[neighbor]--;
                if (deg[neighbor] == 1)
                    leaves.push(neighbor);
            }
            
            // mark as removed
            deg[leaf] = 0; 
        }
    }

    // The remaining nodes are the centroids
    vector<int> result;
    while (!leaves.empty()) {
        result.push_back(leaves.front());
        leaves.pop();
    }

    return result;
}


//Driver Code Starts
int main() {
    // Given adjacency list
    vector<vector<int>> adj = {{2}, {2}, {0, 1, 3}, {2, 4}, {3}};

    vector<int> result = findMinHeight(adj);

    for (int r : result)
        cout << r << " ";
    cout << endl;

    return 0;
}

//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;

class GFG {
//Driver Code Ends


    // Find all possible roots with minimum height
    static ArrayList<Integer> findMinHeight(ArrayList<ArrayList<Integer>> adj) {
        int V = adj.size();
    
        // Base case: if less than 2 nodes
        if (V < 2) {
            ArrayList<Integer> centroids = new ArrayList<>();
            for (int i = 0; i < V; i++)
                centroids.add(i);
            return centroids;
        }
    
        // Store degree of each node
        int[] deg = new int[V];
        for (int i = 0; i < V; i++)
            deg[i] = adj.get(i).size();
    
        // Initialize the first layer of leaves
        ArrayList<Integer> leaves = new ArrayList<>();
        for (int i = 0; i < V; i++)
            if (deg[i] == 1)
                leaves.add(i);
    
        int remNodes = V;
    
        // Trim the leaves level by level until reaching the centroids
        while (remNodes > 2) {
            int leafCount = leaves.size();
            remNodes -= leafCount;
    
            ArrayList<Integer> newLeaves = new ArrayList<>();
    
            for (int i = 0; i < leafCount; i++) {
                int leaf = leaves.get(i);
    
                for (int neighbor : adj.get(leaf)) {
                    deg[neighbor]--;
                    if (deg[neighbor] == 1)
                        newLeaves.add(neighbor);
                }
                // mark as removed
                deg[leaf] = 0; 
            }
    
            leaves = newLeaves;
        }
    
        // The remaining nodes are the centroids
        ArrayList<Integer> result = new ArrayList<>();
        for (int leaf : leaves)
            result.add(leaf);
    
        return result;
    }
    

//Driver Code Starts
    
    // Add an undirected edge
    static void addEdge(ArrayList<ArrayList<Integer>> adj, int u, int v) {
        adj.get(u).add(v);
        adj.get(v).add(u);
    }


    public static void main(String[] args) {
        int V = 5;
        ArrayList<ArrayList<Integer>> adj = new ArrayList<>();
        for (int i = 0; i < V; i++)
            adj.add(new ArrayList<>());

        // Add edges
        addEdge(adj, 0, 2);
        addEdge(adj, 1, 2);
        addEdge(adj, 2, 3);
        addEdge(adj, 3, 4);

        ArrayList<Integer> result = findMinHeight(adj);

        for (int r : result)
            System.out.print(r + " ");
        System.out.println();
    }
}

//Driver Code Ends
Python
#Driver Code Starts
from collections import deque
#Driver Code Ends


def findMinHeight(adj):
    V = len(adj)

    # Base case: if less than 2 nodes
    if V < 2:
        centroids = []
        for i in range(V):
            centroids.append(i)
        return centroids

    # Store degree of each node
    deg = [len(adj[i]) for i in range(V)]

    # Initialize the first layer of leaves
    leaves = deque()
    for i in range(V):
        if deg[i] == 1:
            leaves.append(i)

    remNodes = V

    # Trim the leaves level by level until reaching the centroids
    while remNodes > 2:
        leafCount = len(leaves)
        remNodes -= leafCount

        for _ in range(leafCount):
            leaf = leaves.popleft()

            for neighbor in adj[leaf]:
                deg[neighbor] -= 1
                if deg[neighbor] == 1:
                    leaves.append(neighbor)
            deg[leaf] = 0  # mark as removed

    # The remaining nodes are the centroids
    result = []
    while leaves:
        result.append(leaves.popleft())

    return result


#Driver Code Starts

if __name__ == "__main__":
    adj = [[2], [2], [0, 1, 3], [2, 4], [3]]
    
    result = findMinHeight(adj)
    
    for r in result:
        print(r, end=" ")
    print()

#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;

class GFG
{
//Driver Code Ends


    // Find all possible roots with minimum height
    static List<int> findMinHeight(List<List<int>> adj)
    {
        int V = adj.Count;

        // Base case: if less than 2 nodes
        if (V < 2)
        {
            List<int> centroids = new List<int>();
            for (int i = 0; i < V; i++)
                centroids.Add(i);
            return centroids;
        }

        // Store degree of each node
        int[] deg = new int[V];
        for (int i = 0; i < V; i++)
            deg[i] = adj[i].Count;

        // Initialize the first layer of leaves
        Queue<int> leaves = new Queue<int>();
        for (int i = 0; i < V; i++)
            if (deg[i] == 1)
                leaves.Enqueue(i);

        int remNodes = V;

        // Trim the leaves level by level until reaching the centroids
        while (remNodes > 2)
        {
            int leafCount = leaves.Count;
            remNodes -= leafCount;

            for (int i = 0; i < leafCount; i++)
            {
                int leaf = leaves.Dequeue();

                foreach (int neighbor in adj[leaf])
                {
                    deg[neighbor]--;
                    if (deg[neighbor] == 1)
                        leaves.Enqueue(neighbor);
                }
                 // mark as removed
                deg[leaf] = 0;
            }
        }

        // The remaining nodes are the centroids
        List<int> result = new List<int>();
        while (leaves.Count > 0)
            result.Add(leaves.Dequeue());

        return result;
    }
    

//Driver Code Starts
     // Add an undirected edge
    static void addEdge(List<List<int>> adj, int u, int v)
    {
        adj[u].Add(v);
        adj[v].Add(u);
    }

    static void Main()
    {
        int V = 5;
        List<List<int>> adj = new List<List<int>>();
        for (int i = 0; i < V; i++)
            adj.Add(new List<int>());

        // Add edges
        addEdge(adj, 0, 2);
        addEdge(adj, 1, 2);
        addEdge(adj, 2, 3);
        addEdge(adj, 3, 4);

        List<int> result = findMinHeight(adj);

        foreach (int r in result)
            Console.Write(r + " ");
        Console.WriteLine();
    }
}

//Driver Code Ends
JavaScript
function findMinHeight(adj) {
    const V = adj.length;

    // Base case: if less than 2 nodes
    if (V < 2) {
        const centroids = [];
        for (let i = 0; i < V; i++)
            centroids.push(i);
        return centroids;
    }

    // Store degree of each node
    const deg = new Array(V).fill(0);
    for (let i = 0; i < V; i++)
        deg[i] = adj[i].length;

    // Initialize the first layer of leaves
    let leaves = [];
    for (let i = 0; i < V; i++)
        if (deg[i] === 1)
            leaves.push(i);

    let remNodes = V;

    // Trim the leaves level by level until reaching the centroids
    while (remNodes > 2) {
        const leafCount = leaves.length;
        remNodes -= leafCount;
        const newLeaves = [];

        for (let i = 0; i < leafCount; i++) {
            const leaf = leaves[i];

            for (const neighbor of adj[leaf]) {
                deg[neighbor]--;
                if (deg[neighbor] === 1)
                    newLeaves.push(neighbor);
            }
            deg[leaf] = 0; // mark as removed
        }

        leaves = newLeaves;
    }

    // The remaining nodes are the centroids
    return leaves;
}


//Driver Code Starts
// Driver Code
// Given adjacency list
const adj = [[2], [2], [0, 1, 3], [2, 4], [3]];

const result = findMinHeight(adj);

for (const r of result)
    process.stdout.write(r + " ");
console.log();

//Driver Code Ends

Output
2 3 
Comment