[Naive Approach] Recompute Subtree Sum for Every Node - O(n²) Time and O(h) Space
The idea is to treat every node as the root of a subtree. For each node, recursively calculate the sum of all nodes in its subtree and compare it with the maximum subtree sum found so far. Since the subtree sums are computed independently for every node, the same nodes are visited multiple times, resulting in redundant calculations.
C++
#include<bits/stdc++.h>usingnamespacestd;classNode{public:intdata;Node*left,*right;Node(intx){data=x;left=right=nullptr;}};// Returns the sum of the subtree rooted at 'root'.intsubtreeSum(Node*root){if(root==nullptr)return0;returnroot->data+subtreeSum(root->left)+subtreeSum(root->right);}// Traverses all nodes and updates the maximum subtree sum.voiddfs(Node*root,int&ans){if(root==nullptr)return;ans=max(ans,subtreeSum(root));dfs(root->left,ans);dfs(root->right,ans);}intmaxSubtreeSum(Node*root){if(root==nullptr)return0;intans=INT_MIN;dfs(root,ans);returnans;}intmain(){// Representation of the given tree// 1// / \ // -2 3// / \ / \ // 4 5 -6 2Node*root=newNode(1);root->left=newNode(-2);root->right=newNode(3);root->left->left=newNode(4);root->left->right=newNode(5);root->right->left=newNode(-6);root->right->right=newNode(2);cout<<maxSubtreeSum(root);return0;}
Java
classNode{intdata;Nodeleft,right;Node(intx){data=x;left=right=null;}}classMain{// Returns the sum of the subtree rooted at 'root'.staticintsubtreeSum(Noderoot){if(root==null)return0;returnroot.data+subtreeSum(root.left)+subtreeSum(root.right);}// Traverses all nodes and updates the maximum subtree sum.staticvoiddfs(Noderoot,int[]ans){if(root==null)return;ans[0]=Math.max(ans[0],subtreeSum(root));dfs(root.left,ans);dfs(root.right,ans);}staticintmaxSubtreeSum(Noderoot){if(root==null)return0;int[]ans={Integer.MIN_VALUE};dfs(root,ans);returnans[0];}publicstaticvoidmain(String[]args){// Representation of the given tree// 1// / \// -2 3// / \ / \// 4 5 -6 2Noderoot=newNode(1);root.left=newNode(-2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(-6);root.right.right=newNode(2);System.out.print(maxSubtreeSum(root));}}
Python
classNode:def__init__(self,x):self.data=xself.left=Noneself.right=None# Returns the sum of the subtree rooted at 'root'.defsubtreeSum(root):ifrootisNone:return0return(root.data+subtreeSum(root.left)+subtreeSum(root.right))# Traverses all nodes and updates the maximum subtree sum.defdfs(root,ans):ifrootisNone:returnans[0]=max(ans[0],subtreeSum(root))dfs(root.left,ans)dfs(root.right,ans)defmaxSubtreeSum(root):ifrootisNone:return0ans=[float('-inf')]dfs(root,ans)returnans[0]# Representation of the given tree# 1# / \# -2 3# / \ / \# 4 5 -6 2root=Node(1)root.left=Node(-2)root.right=Node(3)root.left.left=Node(4)root.left.right=Node(5)root.right.left=Node(-6)root.right.right=Node(2)print(maxSubtreeSum(root))
C#
usingSystem;classNode{publicintdata;publicNodeleft,right;publicNode(intx){data=x;left=right=null;}}classGFG{// Returns the sum of the subtree rooted at 'root'.staticintsubtreeSum(Noderoot){if(root==null)return0;returnroot.data+subtreeSum(root.left)+subtreeSum(root.right);}// Traverses all nodes and updates the maximum subtree sum.staticvoiddfs(Noderoot,refintans){if(root==null)return;ans=Math.Max(ans,subtreeSum(root));dfs(root.left,refans);dfs(root.right,refans);}staticintmaxSubtreeSum(Noderoot){if(root==null)return0;intans=int.MinValue;dfs(root,refans);returnans;}staticvoidMain(){// Representation of the given tree// 1// / \// -2 3// / \ / \// 4 5 -6 2Noderoot=newNode(1);root.left=newNode(-2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(-6);root.right.right=newNode(2);Console.Write(maxSubtreeSum(root));}}
JavaScript
classNode{constructor(x){this.data=x;this.left=null;this.right=null;}}// Returns the sum of the subtree rooted at 'root'.functionsubtreeSum(root){if(root===null)return0;returnroot.data+subtreeSum(root.left)+subtreeSum(root.right);}// Traverses all nodes and updates the maximum subtree sum.functiondfs(root,ans){if(root===null)return;ans[0]=Math.max(ans[0],subtreeSum(root));dfs(root.left,ans);dfs(root.right,ans);}functionmaxSubtreeSum(root){if(root===null)return0;letans=[-Infinity];dfs(root,ans);returnans[0];}// Representation of the given tree// 1// / \// -2 3// / \ / \// 4 5 -6 2letroot=newNode(1);root.left=newNode(-2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(-6);root.right.right=newNode(2);console.log(maxSubtreeSum(root));
Output
7
[Expected Approach - 1] Using Recursion (Postorder Traversal) - O(n) Time and O(h) Space
The idea is to calculate the subtree sum for every node using postorder traversal. In postorder traversal, we first visit the left subtree, then the right subtree, and finally the current node. This ensures that the subtree sums of both children are already known before processing the current node.
For every node, recursively find the sum of its left and right subtrees. Then, add these sums to the current node's value to get the subtree sum rooted at that node. While computing these sums, keep track of the largest subtree sum found so far.
Consider the following binary tree:
The tree is processed in postorder (Left -> Right -> Root): 4 -> 5 -> -2 -> -6 -> 2 -> 3 -> 1
Subtree sums are computed while returning from recursion:
Node 4 -> Leaf node, so subtree sum = 4.
Node 5 -> Leaf node, so subtree sum = 5.
Node -6 -> Leaf node, so subtree sum = -6.
Node 2 -> Leaf node, so subtree sum = 2.
Node -2 -> Add left and right subtree sums: -2 + 4 + 5 = 7.
Node 3 -> Add left and right subtree sums: 3 + (-6) + 2 = -1.
Node 1 -> Add left and right subtree sums: 1 + 7 + (-1) = 7.
The subtree rooted at node -2 has the largest sum, which is 7. Hence, the largest subtree sum is 7.
C++
#include<bits/stdc++.h>usingnamespacestd;classNode{public:intdata;Node*left,*right;Node(intx){data=x;left=right=nullptr;}};// Helper function to find largest// subtree sum recursively.intfindLargestSubtreeSumUtil(Node*root,int&ans){// If current node is null then// return 0 to parent node.if(root==nullptr)return0;// Subtree sum rooted at current node.intcurrSum=root->data+findLargestSubtreeSumUtil(root->left,ans)+findLargestSubtreeSumUtil(root->right,ans);// Update answer if current subtree// sum is greater than answer so far.ans=max(ans,currSum);// Return current subtree sum to// its parent node.returncurrSum;}intmaxSubtreeSum(Node*root){// If tree does not exist, // then answer is 0.if(root==nullptr)return0;intans=INT_MIN;findLargestSubtreeSumUtil(root,ans);returnans;}intmain(){// Representation of the given tree// 1// / \ // -2 3// / \ / \ // 4 5 -6 2Node*root=newNode(1);root->left=newNode(-2);root->right=newNode(3);root->left->left=newNode(4);root->left->right=newNode(5);root->right->left=newNode(-6);root->right->right=newNode(2);cout<<maxSubtreeSum(root);return0;}
Java
classNode{intdata;Nodeleft,right;Node(intx){data=x;left=right=null;}}classGFG{// Helper function to find largest// subtree sum recursively.staticintfindLargestSubtreeSumUtil(Noderoot,int[]ans){// If current node is null then// return 0 to parent node.if(root==null)return0;// Subtree sum rooted at current node.intcurrSum=root.data+findLargestSubtreeSumUtil(root.left,ans)+findLargestSubtreeSumUtil(root.right,ans);// Update answer if current subtree// sum is greater than answer so far.ans[0]=Math.max(ans[0],currSum);// Return current subtree sum to// its parent node.returncurrSum;}staticintmaxSubtreeSum(Noderoot){// If tree does not exist,// then answer is 0.if(root==null)return0;int[]ans={Integer.MIN_VALUE};findLargestSubtreeSumUtil(root,ans);returnans[0];}publicstaticvoidmain(String[]args){// Representation of the given tree// 1// / \// -2 3// / \ / \// 4 5 -6 2Noderoot=newNode(1);root.left=newNode(-2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(-6);root.right.right=newNode(2);System.out.print(maxSubtreeSum(root));}}
Python
classNode:def__init__(self,x):self.data=xself.left=Noneself.right=None# Helper function to find largest# subtree sum recursively.deffindLargestSubtreeSumUtil(root,ans):# If current node is null then# return 0 to parent node.ifrootisNone:return0# Subtree sum rooted at current node.currSum=(root.data+findLargestSubtreeSumUtil(root.left,ans)+findLargestSubtreeSumUtil(root.right,ans))# Update answer if current subtree# sum is greater than answer so far.ans[0]=max(ans[0],currSum)# Return current subtree sum to# its parent node.returncurrSumdefmaxSubtreeSum(root):# If tree does not exist,# then answer is 0.ifrootisNone:return0ans=[float('-inf')]findLargestSubtreeSumUtil(root,ans)returnans[0]# Representation of the given tree# 1# / \# -2 3# / \ / \# 4 5 -6 2root=Node(1)root.left=Node(-2)root.right=Node(3)root.left.left=Node(4)root.left.right=Node(5)root.right.left=Node(-6)root.right.right=Node(2)print(maxSubtreeSum(root))
C#
usingSystem;classNode{publicintdata;publicNodeleft,right;publicNode(intx){data=x;left=right=null;}}classGFG{// Helper function to find largest// subtree sum recursively.staticintfindLargestSubtreeSumUtil(Noderoot,refintans){// If current node is null then// return 0 to parent node.if(root==null)return0;// Subtree sum rooted at current node.intcurrSum=root.data+findLargestSubtreeSumUtil(root.left,refans)+findLargestSubtreeSumUtil(root.right,refans);// Update answer if current subtree// sum is greater than answer so far.ans=Math.Max(ans,currSum);// Return current subtree sum to// its parent node.returncurrSum;}staticintmaxSubtreeSum(Noderoot){// If tree does not exist,// then answer is 0.if(root==null)return0;intans=int.MinValue;findLargestSubtreeSumUtil(root,refans);returnans;}staticvoidMain(){// Representation of the given tree// 1// / \// -2 3// / \ / \// 4 5 -6 2Noderoot=newNode(1);root.left=newNode(-2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(-6);root.right.right=newNode(2);Console.Write(maxSubtreeSum(root));}}
JavaScript
classNode{constructor(x){this.data=x;this.left=null;this.right=null;}}// Helper function to find largest// subtree sum recursively.functionfindLargestSubtreeSumUtil(root,ans){// If current node is null then// return 0 to parent node.if(root===null)return0;// Subtree sum rooted at current node.letcurrSum=root.data+findLargestSubtreeSumUtil(root.left,ans)+findLargestSubtreeSumUtil(root.right,ans);// Update answer if current subtree// sum is greater than answer so far.ans[0]=Math.max(ans[0],currSum);// Return current subtree sum to// its parent node.returncurrSum;}functionmaxSubtreeSum(root){// If tree does not exist,// then answer is 0.if(root===null)return0;letans=[-Infinity];findLargestSubtreeSumUtil(root,ans);returnans[0];}// Representation of the given tree// 1// / \// -2 3// / \ / \// 4 5 -6 2letroot=newNode(1);root.left=newNode(-2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(-6);root.right.right=newNode(2);console.log(maxSubtreeSum(root));
Output
7
[Expected Approach - 2] Using BFS (Level Order Traversal) - O(n) Time and O(n) Space
The idea is to first perform a level order traversal (BFS) and store the nodes level by level. Then, process the stored levels in reverse order (from bottom to top).
For each node, compute its subtree sum by adding its own value and the subtree sums of its left and right children, which have already been calculated. While computing these sums, keep updating the maximum subtree sum.
Consider the following binary tree:
Step 1: Store Nodes Level Wise
Using BFS, store the nodes at each level.
Level 0 : [1]
Level 1 : [-2, 3]
Level 2 : [4, 5, -6, 2]
Now process the levels from bottom to top.
Step 2: Process Level 2
These are leaf nodes, so their subtree sums are their own values.
subtreeSum[4] = 4
subtreeSum[5] = 5
subtreeSum[-6] = -6
subtreeSum[2] = 2
Maximum subtree sum = 5
Step 3: Process Level 1
For node -2: subtreeSum[-2] = -2 + 4 + 5 = 7
Maximum subtree sum = 7
For node 3: subtreeSum[3] = 3 + (-6) + 2 = -1
Maximum subtree sum remains 7.
Step 4: Process Level 0
For the root 1: subtreeSum[1] = 1 + 7 + (-1) = 7
Maximum subtree sum remains 7.
Final Answer:
The subtree sums are:
4 -> 4
5 -> 5
-6 -> -6
2 -> 2
-2 -> 7
3 -> -1
1 -> 7
Hence, the largest subtree sum is 7.
C++
#include<bits/stdc++.h>usingnamespacestd;classNode{public:intdata;Node*left;Node*right;Node(intx){data=x;left=nullptr;right=nullptr;}};intmaxSubtreeSum(Node*root){// Base case when tree is emptyif(root==nullptr)return0;intans=INT_MIN;queue<Node*>q;// Vector of Vector for storing// nodes at a particular levelvector<vector<Node*>>levels;// Map for storing sum of subtree // rooted at a particular nodeunordered_map<Node*,int>subtreeSum;// Push root to the queueq.push(root);while(!q.empty()){intn=q.size();vector<Node*>level;while(n--){Node*node=q.front();// Push current node to current// level vectorlevel.push_back(node);// Add left & right child of node// in the queueif(node->left)q.push(node->left);if(node->right)q.push(node->right);q.pop();}// add current level to levels// vectorlevels.push_back(level);}// Traverse all levels from bottom//most level to top most levelfor(inti=levels.size()-1;i>=0;i--){for(autoe:levels[i]){// add value of current nodesubtreeSum[e]=e->data;// If node has left child, add the subtree sum// of subtree rooted at left childif(e->left)subtreeSum[e]+=subtreeSum[e->left];// If node has right child, add the subtree sum// of subtree rooted at right childif(e->right)subtreeSum[e]+=subtreeSum[e->right];// update ans to maximum of ans and sum of// subtree rooted at current nodeans=max(ans,subtreeSum[e]);}}returnans;}intmain(){// Representation of the given tree// 1// / \ // -2 3// / \ / \ // 4 5 -6 2Node*root=newNode(1);root->left=newNode(-2);root->right=newNode(3);root->left->left=newNode(4);root->left->right=newNode(5);root->right->left=newNode(-6);root->right->right=newNode(2);cout<<maxSubtreeSum(root)<<endl;return0;}
Java
importjava.util.*;classNode{intdata;Nodeleft;Noderight;Node(intx){data=x;left=null;right=null;}}classGfG{publicstaticintmaxSubtreeSum(Noderoot){// Base case when tree is emptyif(root==null)return0;intans=Integer.MIN_VALUE;// Queue for level order traversalQueue<Node>q=newLinkedList<>();// List of List for storing// nodes at a particular levelList<List<Node>>levels=newArrayList<>();// Map for storing sum of subtree // rooted at a particular nodeHashMap<Node,Integer>subtreeSum=newHashMap<>();q.add(root);while(!q.isEmpty()){intn=q.size();List<Node>level=newArrayList<>();while(n-->0){Nodenode=q.poll();// Push current node to current // level listlevel.add(node);// Add left & right child of node// in the queueif(node.left!=null)q.add(node.left);if(node.right!=null)q.add(node.right);}// add current level to// levels listlevels.add(level);}// Traverse all levels from bottom // most level to top most levelfor(inti=levels.size()-1;i>=0;i--){for(Nodee:levels.get(i)){// add value of current nodesubtreeSum.put(e,e.data);// If node has left child, add the subtree sum// of subtree rooted at left childif(e.left!=null)subtreeSum.put(e,subtreeSum.get(e)+subtreeSum.get(e.left));// If node has right child, add the subtree sum// of subtree rooted at right childif(e.right!=null)subtreeSum.put(e,subtreeSum.get(e)+subtreeSum.get(e.right));// update ans to maximum of ans and sum of// subtree rooted at current nodeans=Math.max(ans,subtreeSum.get(e));}}returnans;}publicstaticvoidmain(String[]args){// Representation of the given tree// 1// / \// -2 3// / \ / \// 4 5 -6 2Noderoot=newNode(1);root.left=newNode(-2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(-6);root.right.right=newNode(2);System.out.println(maxSubtreeSum(root));}}
Python
classNode:def__init__(self,x):self.data=xself.left=Noneself.right=NonedefmaxSubtreeSum(root):# Base case when tree is emptyifrootisNone:return0ans=float('-inf')# Queue for level order# traversalq=[]# List of List for storing# nodes at a particular levellevels=[]# Dictionary for storing sum of subtree # rooted at a particular nodesubtreeSum={}# Push root to the queueq.append(root)whileq:n=len(q)level=[]whilen>0:node=q.pop(0)# Push current node to current# level listlevel.append(node)# Add left & right child of node# in the queueifnode.left:q.append(node.left)ifnode.right:q.append(node.right)n-=1# add current level to # levels listlevels.append(level)# Traverse all levels from bottom most level to top# most levelforiinrange(len(levels)-1,-1,-1):foreinlevels[i]:# add value of current nodesubtreeSum[e]=e.data# If node has left child, add the subtree sum# of subtree rooted at left childife.left:subtreeSum[e]+=subtreeSum[e.left]# If node has right child, add the subtree sum# of subtree rooted at right childife.right:subtreeSum[e]+=subtreeSum[e.right]# update ans to maximum of ans and sum of# subtree rooted at current nodeans=max(ans,subtreeSum[e])returnansif__name__=="__main__":# Representation of the given tree# 1# / \# -2 3# / \ / \# 4 5 -6 2root=Node(1)root.left=Node(-2)root.right=Node(3)root.left.left=Node(4)root.left.right=Node(5)root.right.left=Node(-6)root.right.right=Node(2)print(maxSubtreeSum(root))
C#
usingSystem;usingSystem.Collections.Generic;classNode{publicintdata;publicNodeleft;publicNoderight;publicNode(intx){data=x;left=null;right=null;}}classGfG{publicstaticintmaxSubtreeSum(Noderoot){// Base case when tree is emptyif(root==null)return0;intans=int.MinValue;// Queue for level order traversalQueue<Node>q=newQueue<Node>();// List of List for storing// nodes at a particular levelList<List<Node>>levels=newList<List<Node>>();// Dictionary for storing sum of subtree // rooted at a particular nodeDictionary<Node,int>subtreeSum=newDictionary<Node,int>();// Push root to the queueq.Enqueue(root);while(q.Count>0){intn=q.Count;List<Node>level=newList<Node>();while(n-->0){Nodenode=q.Dequeue();// Push current node to current// level listlevel.Add(node);// Add left & right child of node// in the queueif(node.left!=null)q.Enqueue(node.left);if(node.right!=null)q.Enqueue(node.right);}// add current level to // levels listlevels.Add(level);}// Traverse all levels from bottom // most level to top most levelfor(inti=levels.Count-1;i>=0;i--){foreach(vareinlevels[i]){// add value of current nodesubtreeSum[e]=e.data;// If node has left child, add the subtree sum// of subtree rooted at left childif(e.left!=null)subtreeSum[e]+=subtreeSum[e.left];// If node has right child, add the subtree sum// of subtree rooted at right childif(e.right!=null)subtreeSum[e]+=subtreeSum[e.right];// update ans to maximum of ans and sum of// subtree rooted at current nodeans=Math.Max(ans,subtreeSum[e]);}}returnans;}publicstaticvoidMain(){// Representation of the given tree// 1// / \// -2 3// / \ / \// 4 5 -6 2Noderoot=newNode(1);root.left=newNode(-2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(-6);root.right.right=newNode(2);Console.WriteLine(maxSubtreeSum(root));}}
JavaScript
classNode{constructor(x){this.data=x;this.left=null;this.right=null;}}functionmaxSubtreeSum(root){// Base case when tree is emptyif(root===null)return0;letans=Number.NEGATIVE_INFINITY;// Queue for level order traversalconstq=[];// Array of Array for storing// nodes at a particular levelconstlevels=[];// Map for storing sum of subtree // rooted at a particular nodeconstsubtreeSum=newMap();// Push root to the queueq.push(root);while(q.length>0){constn=q.length;constlevel=[];for(leti=0;i<n;i++){constnode=q.shift();// Push current node to current // level arraylevel.push(node);// Add left & right child of node// in the queueif(node.left)q.push(node.left);if(node.right)q.push(node.right);}// add current level to levels arraylevels.push(level);}// Traverse all levels from bottom most level to top// most levelfor(leti=levels.length-1;i>=0;i--){for(consteoflevels[i]){// add value of current nodesubtreeSum.set(e,e.data);// If node has left child, add the subtree sum// of subtree rooted at left childif(e.left)subtreeSum.set(e,subtreeSum.get(e)+subtreeSum.get(e.left));// If node has right child, add the subtree sum// of subtree rooted at right childif(e.right)subtreeSum.set(e,subtreeSum.get(e)+subtreeSum.get(e.right));// update ans to maximum of ans and sum of// subtree rooted at current nodeans=Math.max(ans,subtreeSum.get(e));}}returnans;}// Driver code// Representation of the given tree// 1// / \// -2 3// / \ / \// 4 5 -6 2constroot=newNode(1);root.left=newNode(-2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(-6);root.right.right=newNode(2);console.log(maxSubtreeSum(root));