Maximum height of Tree when any Node can be considered as Root
Last Updated : 03 Dec, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report
Given a tree with n nodes and n-1 edges, the task is to find the maximum height of the tree when any node in the tree is considered as the root of the tree.
Example:
Input:
Output: 5 Explanation: The below diagram represents a tree with 11 nodes and 10 edges and the path that gives us the maximum height when node 1 is considered as a root. The maximum height is 3.
Input:
Output: 4 Explanation: The below diagram represents a tree with 11 nodes and 10 edges and the path that gives us the maximum height when node 2 is considered as a root.
Using Dynamic Programming - O(n) Time and O(n) Space
A naive approach would be to traverse the tree using DFS traversal for every node and calculate the maximum height when the node is treated as the root of the tree.
The above problem can be solved by using Dynamic Programming on Trees. To solve this problem, pre-calculate two things for every node. One will be the maximum height while traveling downwards via its branches to the leaves. While the other will be the maximum height when traveling upwards via its parent to any of the leaves.
Optimal Substructure:
When node i is considered as a root,
in[i] be the maximum height of the tree when we travel downwards via its sub-trees and leaves.
out[i] be the maximum height of the tree while traveling upwards via its parent.
The maximum height of a tree when node i is considered as a root will be max(in[i], out[i]).
The below is the calculation of in[i]:
In the image above, values in[i] have been calculated for every node i. The maximum of every subtree is taken and added with 1 to the parent of that subtree. Add 1 for the edge between parent and subtree. Traverse the tree using DFS and calculate in[i] as max(in[i], 1+ in[child]) for every node.
The below is the calculation of out[i]:
The above diagram shows all the out[i] values (path for all the out[i] is shown below). For calculation of out[i], move upwards to the parent of node i. From the parent of node i, there are two ways to move in, one will be in all the branches of the parent. The other direction is to move to the parent(call it parent2 to avoid confusion) of the parent(call it parent1) of node i. The maximum height upwards via parent2 is out[parent1] itself. Generally, out[node i] as 1+max(out[i], 1+max of all branches). Add 1 for the edges between node and parent.
Node 1: No other way
Node 2: 2 -> 1 -> 3 -> 7 -> 10
Node 3 = 3 -> 1 -> 4 -> 8
Node 4 = 4 -> 1 -> 3 -> 7 -> 11
Node 5 = 5 -> 2 -> 1 -> 3 -> 7 -> 10
Node 6 = 6 -> 2 -> 1 -> 3 -> 7 -> 10
Node 7 = 7 -> 3 -> 1 -> 4 -> 9
Node 8 = 8 -> 4 -> 1 -> 3 -> 7 -> 11
Node 9 = 9 -> 4 -> 1 -> 3 -> 7 -> 11
Node 10 = 10-> 7 -> 3 -> 1 -> 2 -> 6
Node 11 = 11 -> 7 -> 3 -> 1 -> 4 -> 8
The above diagram explains the calculation of out[i] when 2 is considered as the root of the tree. The branches of node 2 are not taken into count since the maximum height via that path has already been calculated and stored in in[2]. Moving up, in this case, the parent of 2, i.e., 1, has no parent. So, the branches except for the one which has the node are considered while calculating the maximum.
The above diagram explains the calculation of out[10]. The parent of node 10, i.e., 7 has a parent and a branch(precisely a child in this case). So the maximum height of both has been taken to count in such cases when parent and branches exist.
In case of multiple branches of a parent, take the longest of them to count(excluding the branch in which the node lies)
Calculating the maximum height of all the branches connected to parent :
in[i] stores the maximum height while moving downwards. No need to store all the lengths of branches. Only the first and second maximum length among all the branches will give the answer. Since the algorithm used is based on DFS, all the branches connected to the parent will be considered, including the branch which has the node. If the first maximum path thus obtained is the same as in[i], then maximum1 is the length of the branch in which node i lies. In this case, our longest path will be maximum2. Recurrence relation of in[i] and out[i]:
in[i] = max(in[i], 1 + in[child])
out[i] = 1 + max(out[parent of i], longest path of all branches of parent of i)
C++
// C++ code to find the maximum path length// considering any node as root#include<bits/stdc++.h>usingnamespacestd;classNode{public:intdata;vector<Node*>children;Node(intx){data=x;}};// function to pre-calculate the in[]// which stores the maximum height when travelled// via branchesintdfs1(Node*root,unordered_map<Node*,int>&in){intans=0;for(Node*child:root->children){ans=max(ans,1+dfs1(child,in));}returnin[root]=ans;}// function to pre-calculate the array out[]// which stores the maximum height when traveled// via parentvoiddfs2(Node*root,unordered_map<Node*,int>&out,unordered_map<Node*,int>&in){// stores the longest and second // longest branchesintmx1=-1,mx2=-1;// traverse in the subtrees of rootfor(Node*child:root->children){// compare and store the longest// and second longestif(in[child]>=mx1){mx2=mx1;mx1=in[child];}elseif(in[child]>mx2)mx2=in[child];}// traverse in the subtree of rootfor(Node*child:root->children){intlongest=mx1;// if longest branch has the node, then// consider the second longest branchif(mx1==in[child])longest=mx2;// recursively calculate out[i]out[child]=1+max(out[root],1+longest);// dfs function calldfs2(child,out,in);}}// function to get maximum height.intmaxHeight(Node*root){unordered_map<Node*,int>in,out;// traversal to calculate in valuesdfs1(root,in);// traversal to calculate out valuesdfs2(root,out,in);intans=0;for(autop:in){Node*node=p.first;ans=max({ans,in[node],out[node]});}returnans;}intmain(){Node*root=newNode(1);Node*node1=newNode(2);Node*node2=newNode(3);Node*node3=newNode(4);Node*node4=newNode(5);Node*node5=newNode(6);Node*node6=newNode(7);Node*node7=newNode(8);Node*node8=newNode(9);Node*node9=newNode(10);Node*node10=newNode(11);root->children.push_back(node1);root->children.push_back(node2);root->children.push_back(node3);node1->children.push_back(node4);node1->children.push_back(node5);node2->children.push_back(node6);node3->children.push_back(node7);node3->children.push_back(node8);node6->children.push_back(node9);node6->children.push_back(node10);cout<<maxHeight(root);return0;}
Java
// Java program to find the maximum path length// considering any node as rootimportjava.util.*;classNode{intdata;ArrayList<Node>children;Node(intx){data=x;children=newArrayList<>();}}classGfG{// function to pre-calculate the in[]// which stores the maximum height when travelled// via branchesstaticintdfs1(Noderoot,HashMap<Node,Integer>in){intans=0;for(Nodechild:root.children){ans=Math.max(ans,1+dfs1(child,in));}in.put(root,ans);returnans;}// function to pre-calculate the array out[]// which stores the maximum height when traveled// via parentstaticvoiddfs2(Noderoot,HashMap<Node,Integer>out,HashMap<Node,Integer>in){// stores the longest and second// longest branchesintmx1=-1,mx2=-1;// traverse in the subtrees of rootfor(Nodechild:root.children){// compare and store the longest// and second longestif(in.get(child)>=mx1){mx2=mx1;mx1=in.get(child);}elseif(in.get(child)>mx2){mx2=in.get(child);}}// traverse in the subtree of rootfor(Nodechild:root.children){intlongest=mx1;// if longest branch has the node, then// consider the second longest branchif(mx1==in.get(child))longest=mx2;// recursively calculate out[i]out.put(child,1+Math.max(out.getOrDefault(root,0),1+longest));// dfs function calldfs2(child,out,in);}}// function to get maximum height.staticintmaxHeight(Noderoot){HashMap<Node,Integer>in=newHashMap<>();HashMap<Node,Integer>out=newHashMap<>();// traversal to calculate in valuesdfs1(root,in);// traversal to calculate out valuesdfs2(root,out,in);intans=0;for(Nodenode:in.keySet()){ans=Math.max(ans,Math.max(in.get(node),out.getOrDefault(node,0)));}returnans;}publicstaticvoidmain(String[]args){Noderoot=newNode(1);Nodenode1=newNode(2);Nodenode2=newNode(3);Nodenode3=newNode(4);Nodenode4=newNode(5);Nodenode5=newNode(6);Nodenode6=newNode(7);Nodenode7=newNode(8);Nodenode8=newNode(9);Nodenode9=newNode(10);Nodenode10=newNode(11);root.children.add(node1);root.children.add(node2);root.children.add(node3);node1.children.add(node4);node1.children.add(node5);node2.children.add(node6);node3.children.add(node7);node3.children.add(node8);node6.children.add(node9);node6.children.add(node10);System.out.println(maxHeight(root));}}
Python
# Python program to find the maximum path length# considering any node as rootclassNode:def__init__(self,x):self.data=xself.children=[]# function to pre-calculate the in[]# which stores the maximum height when travelled# via branchesdefdfs1(root,in_):ans=0forchildinroot.children:ans=max(ans,1+dfs1(child,in_))in_[root]=ansreturnans# function to pre-calculate the array out[]# which stores the maximum height when traveled# via parentdefdfs2(root,out,in_):# stores the longest and second# longest branchesmx1,mx2=-1,-1# traverse in the subtrees of rootforchildinroot.children:# compare and store the longest# and second longestifin_[child]>=mx1:mx2=mx1mx1=in_[child]elifin_[child]>mx2:mx2=in_[child]# traverse in the subtree of rootforchildinroot.children:longest=mx1# if longest branch has the node, then# consider the second longest branchifmx1==in_[child]:longest=mx2# recursively calculate out[i]out[child]=1+max(out.get(root,0),1+longest)# dfs function calldfs2(child,out,in_)# function to get maximum height.defmaxHeight(root):in_={}out={}# traversal to calculate in valuesdfs1(root,in_)# traversal to calculate out valuesdfs2(root,out,in_)ans=0fornodeinin_:ans=max(ans,in_[node],out.get(node,0))returnansif__name__=="__main__":root=Node(1)node1=Node(2)node2=Node(3)node3=Node(4)node4=Node(5)node5=Node(6)node6=Node(7)node7=Node(8)node8=Node(9)node9=Node(10)node10=Node(11)root.children.extend([node1,node2,node3])node1.children.extend([node4,node5])node2.children.append(node6)node3.children.extend([node7,node8])node6.children.extend([node9,node10])print(maxHeight(root))
C#
// C# program to find the maximum path length// considering any node as rootusingSystem;usingSystem.Collections.Generic;classNode{publicintdata;publicList<Node>children;publicNode(intx){data=x;children=newList<Node>();}}classGfG{// function to pre-calculate the in[]// which stores the maximum height when travelled// via branchesstaticintdfs1(Noderoot,Dictionary<Node,int>inMap){intans=0;foreach(Nodechildinroot.children){ans=Math.Max(ans,1+dfs1(child,inMap));}inMap[root]=ans;returnans;}// function to pre-calculate the array out[]// which stores the maximum height when traveled// via parentstaticvoiddfs2(Noderoot,Dictionary<Node,int>outMap,Dictionary<Node,int>inMap){// stores the longest and second// longest branchesintmx1=-1,mx2=-1;// traverse in the subtrees of rootforeach(Nodechildinroot.children){// compare and store the longest// and second longestif(inMap[child]>=mx1){mx2=mx1;mx1=inMap[child];}elseif(inMap[child]>mx2){mx2=inMap[child];}}// traverse in the subtree of rootforeach(Nodechildinroot.children){intlongest=mx1;// if longest branch has the node, then// consider the second longest branchif(mx1==inMap[child])longest=mx2;// recursively calculate out[i]outMap[child]=1+Math.Max(outMap.ContainsKey(root)?outMap[root]:0,1+longest);// dfs function calldfs2(child,outMap,inMap);}}// function to get maximum height.staticintmaxHeight(Noderoot){varinMap=newDictionary<Node,int>();varoutMap=newDictionary<Node,int>();// traversal to calculate in valuesdfs1(root,inMap);// traversal to calculate out valuesdfs2(root,outMap,inMap);intans=0;foreach(varnodeininMap.Keys){ans=Math.Max(ans,Math.Max(inMap[node],outMap.ContainsKey(node)?outMap[node]:0));}returnans;}staticvoidMain(string[]args){Noderoot=newNode(1);Nodenode1=newNode(2);Nodenode2=newNode(3);Nodenode3=newNode(4);Nodenode4=newNode(5);Nodenode5=newNode(6);Nodenode6=newNode(7);Nodenode7=newNode(8);Nodenode8=newNode(9);Nodenode9=newNode(10);Nodenode10=newNode(11);root.children.Add(node1);root.children.Add(node2);root.children.Add(node3);node1.children.Add(node4);node1.children.Add(node5);node2.children.Add(node6);node3.children.Add(node7);node3.children.Add(node8);node6.children.Add(node9);node6.children.Add(node10);Console.WriteLine(maxHeight(root));}}
JavaScript
// JavaScript program to find the maximum path length// considering any node as rootclassNode{constructor(x){this.data=x;this.children=[];}}// function to pre-calculate the in[]// which stores the maximum height when travelled// via branchesfunctiondfs1(root,inMap){letans=0;for(constchildofroot.children){ans=Math.max(ans,1+dfs1(child,inMap));}inMap.set(root,ans);returnans;}// function to pre-calculate the array out[]// which stores the maximum height when traveled// via parentfunctiondfs2(root,outMap,inMap){// stores the longest and second// longest branchesletmx1=-1,mx2=-1;// traverse in the subtrees of rootfor(constchildofroot.children){// compare and store the longest// and second longestif(inMap.get(child)>=mx1){mx2=mx1;mx1=inMap.get(child);}elseif(inMap.get(child)>mx2){mx2=inMap.get(child);}}// traverse in the subtree of rootfor(constchildofroot.children){letlongest=mx1;// if longest branch has the node, then// consider the second longest branchif(mx1===inMap.get(child)){longest=mx2;}// recursively calculate out[i]outMap.set(child,1+Math.max(outMap.get(root)||0,1+longest));// dfs function calldfs2(child,outMap,inMap);}}// function to get maximum height.functionmaxHeight(root){constinMap=newMap();constoutMap=newMap();// traversal to calculate in valuesdfs1(root,inMap);// traversal to calculate out valuesdfs2(root,outMap,inMap);letans=0;for(const[node,val]ofinMap){ans=Math.max(ans,val,outMap.get(node)||0);}returnans;}constroot=newNode(1);constnode1=newNode(2);constnode2=newNode(3);constnode3=newNode(4);constnode4=newNode(5);constnode5=newNode(6);constnode6=newNode(7);constnode7=newNode(8);constnode8=newNode(9);constnode9=newNode(10);constnode10=newNode(11);root.children.push(node1,node2,node3);node1.children.push(node4,node5);node2.children.push(node6);node3.children.push(node7,node8);node6.children.push(node9,node10);console.log(maxHeight(root));
Output
5
Using Diameter of Tree - O(n) Time and O(h) Space
The idea of this approach is based on the property that the maximum height of a tree, when rooted at any node, is equal to the tree's diameter (the longest path between any two nodes).
C++
// C++ code to find the maximum path length// considering any node as root#include<bits/stdc++.h>usingnamespacestd;classNode{public:intdata;vector<Node*>children;Node(intx){data=x;}};// Function to get diameter of tree.intdiameter(Node*root,int&ans){// variables to get the 2 longest// paths from current node.intmx1=0,mx2=0;for(Node*child:root->children){intval=1+diameter(child,ans);if(val>mx1){mx2=mx1;mx1=val;}elseif(val>mx2){mx2=val;}}ans=max(ans,mx1+mx2);returnmx1;}// function to get maximum height.intmaxHeight(Node*root){intans=0;diameter(root,ans);returnans;}intmain(){Node*root=newNode(1);Node*node1=newNode(2);Node*node2=newNode(3);Node*node3=newNode(4);Node*node4=newNode(5);Node*node5=newNode(6);Node*node6=newNode(7);Node*node7=newNode(8);Node*node8=newNode(9);Node*node9=newNode(10);Node*node10=newNode(11);root->children.push_back(node1);root->children.push_back(node2);root->children.push_back(node3);node1->children.push_back(node4);node1->children.push_back(node5);node2->children.push_back(node6);node3->children.push_back(node7);node3->children.push_back(node8);node6->children.push_back(node9);node6->children.push_back(node10);cout<<maxHeight(root);return0;}
Java
// Java program to find the maximum path length// considering any node as rootimportjava.util.ArrayList;classNode{intdata;ArrayList<Node>children;Node(intx){data=x;children=newArrayList<>();}}classGfG{// Function to get diameter of tree.staticintdiameter(Noderoot,int[]ans){// variables to get the 2 longest// paths from current node.intmx1=0,mx2=0;for(Nodechild:root.children){intval=1+diameter(child,ans);if(val>mx1){mx2=mx1;mx1=val;}elseif(val>mx2){mx2=val;}}ans[0]=Math.max(ans[0],mx1+mx2);returnmx1;}// function to get maximum height.staticintmaxHeight(Noderoot){int[]ans=newint[1];diameter(root,ans);returnans[0];}publicstaticvoidmain(String[]args){Noderoot=newNode(1);Nodenode1=newNode(2);Nodenode2=newNode(3);Nodenode3=newNode(4);Nodenode4=newNode(5);Nodenode5=newNode(6);Nodenode6=newNode(7);Nodenode7=newNode(8);Nodenode8=newNode(9);Nodenode9=newNode(10);Nodenode10=newNode(11);root.children.add(node1);root.children.add(node2);root.children.add(node3);node1.children.add(node4);node1.children.add(node5);node2.children.add(node6);node3.children.add(node7);node3.children.add(node8);node6.children.add(node9);node6.children.add(node10);System.out.println(maxHeight(root));}}
Python
# Python program to find the maximum path length# considering any node as rootclassNode:def__init__(self,x):self.data=xself.children=[]# Function to get diameter of tree.defdiameter(root,ans):# variables to get the 2 longest# paths from current node.mx1=0mx2=0forchildinroot.children:val=1+diameter(child,ans)ifval>mx1:mx2=mx1mx1=valelifval>mx2:mx2=valans[0]=max(ans[0],mx1+mx2)returnmx1# function to get maximum height.defmaxHeight(root):ans=[0]diameter(root,ans)returnans[0]if__name__=="__main__":root=Node(1)node1=Node(2)node2=Node(3)node3=Node(4)node4=Node(5)node5=Node(6)node6=Node(7)node7=Node(8)node8=Node(9)node9=Node(10)node10=Node(11)root.children.extend([node1,node2,node3])node1.children.extend([node4,node5])node2.children.append(node6)node3.children.extend([node7,node8])node6.children.extend([node9,node10])print(maxHeight(root))
C#
// C# program to find the maximum path length// considering any node as rootusingSystem;usingSystem.Collections.Generic;classNode{publicintdata;publicList<Node>children;publicNode(intx){data=x;children=newList<Node>();}}classGfG{// Function to get diameter of tree.staticintdiameter(Noderoot,refintans){// variables to get the 2 longest// paths from current node.intmx1=0,mx2=0;foreach(Nodechildinroot.children){intval=1+diameter(child,refans);if(val>mx1){mx2=mx1;mx1=val;}elseif(val>mx2){mx2=val;}}ans=Math.Max(ans,mx1+mx2);returnmx1;}// function to get maximum height.staticintmaxHeight(Noderoot){intans=0;diameter(root,refans);returnans;}staticvoidMain(string[]args){Noderoot=newNode(1);Nodenode1=newNode(2);Nodenode2=newNode(3);Nodenode3=newNode(4);Nodenode4=newNode(5);Nodenode5=newNode(6);Nodenode6=newNode(7);Nodenode7=newNode(8);Nodenode8=newNode(9);Nodenode9=newNode(10);Nodenode10=newNode(11);root.children.Add(node1);root.children.Add(node2);root.children.Add(node3);node1.children.Add(node4);node1.children.Add(node5);node2.children.Add(node6);node3.children.Add(node7);node3.children.Add(node8);node6.children.Add(node9);node6.children.Add(node10);Console.WriteLine(maxHeight(root));}}
JavaScript
// JavaScript program to find the maximum path length// considering any node as rootclassNode{constructor(x){this.data=x;this.children=[];}}// Function to get diameter of tree.functiondiameter(root,ans){// variables to get the 2 longest// paths from current node.letmx1=0,mx2=0;for(constchildofroot.children){letval=1+diameter(child,ans);if(val>mx1){mx2=mx1;mx1=val;}elseif(val>mx2){mx2=val;}}ans[0]=Math.max(ans[0],mx1+mx2);returnmx1;}// function to get maximum height.functionmaxHeight(root){letans=[0];diameter(root,ans);returnans[0];}constroot=newNode(1);constnode1=newNode(2);constnode2=newNode(3);constnode3=newNode(4);constnode4=newNode(5);constnode5=newNode(6);constnode6=newNode(7);constnode7=newNode(8);constnode8=newNode(9);constnode9=newNode(10);constnode10=newNode(11);root.children.push(node1,node2,node3);node1.children.push(node4,node5);node2.children.push(node6);node3.children.push(node7,node8);node6.children.push(node9,node10);console.log(maxHeight(root));
We use cookies to ensure you have the best browsing experience on our website. By using our site, you
acknowledge that you have read and understood our
Cookie Policy &
Privacy Policy
Improvement
Suggest Changes
Help us improve. Share your suggestions to enhance the article. Contribute your expertise and make a difference in the GeeksforGeeks portal.
Create Improvement
Enhance the article with your expertise. Contribute to the GeeksforGeeks community and help create better learning resources for all.