Given the root of a binary tree, where each node contains an integer value, find the maximum possible path sum between any two leaf nodes. If the tree has fewer than two leaf nodes, return -1.
Examples:
Input: root = [3, 4, 5, -10, 4, N, N]
Output: 16 Explanation:
The leaf nodes are -10, 4 (right child of 4), and 5. Possible paths between leaf nodes are: -10 -> 4 -> 3 -> 5 = -10 + 4 + 3 + 5 = 2 -10 -> 4 -> 4 = -10 + 4 + 4 = -2 4 -> 4 -> 3 -> 5 = 4 + 4 + 3 + 5 = 16 Hence, the maximum path sum is obtained from the path 4 -> 4 -> 3 -> 5, giving 16.
Input: root = [-15, 5, 6, -8, 1, 3, 9, 2, -3, N, N, N, N, N, 0, N, N, N, N, 4, -1, N, N, 10]
[Naive Approach] Find Path Between Every Pair of Leaves - O(L ^ 2 * n) Time and O(n) Space
The idea is to first collect all leaf nodes and consider every pair of leaves. For each pair, find their paths from the root and identify their Lowest Common Ancestor (LCA). The path between the two leaves passes through this LCA, so calculate its sum and keep track of the maximum.
Working of the Approach:
Traverse the tree and store all the leaf nodes in a list.
Consider every possible pair of leaf nodes from this list.
For each pair, find the path from the root to both leaves.
Compare the two paths to find their Lowest Common Ancestor (LCA), which is the last common node.
Calculate the path sum by adding the values from both leaves up to the LCA, including the LCA.
Update the maximum path sum if the current path has a larger sum.
After checking all pairs, return the maximum path sum found.
C++
#include<bits/stdc++.h>usingnamespacestd;structNode{intdata;Node*left;Node*right;Node(intval){data=val;left=right=NULL;}};boolfindPath(Node*root,Node*target,vector<Node*>&path){if(root==NULL)returnfalse;path.push_back(root);if(root==target)returntrue;if(findPath(root->left,target,path)||findPath(root->right,target,path))returntrue;path.pop_back();returnfalse;}voidcollectLeaves(Node*root,vector<Node*>&leaves){if(root==NULL)return;if(root->left==NULL&&root->right==NULL){leaves.push_back(root);return;}collectLeaves(root->left,leaves);collectLeaves(root->right,leaves);}intmaxPathSum(Node*root){if(root==NULL)return-1;vector<Node*>leaves;collectLeaves(root,leaves);if(leaves.size()<2)return-1;intans=INT_MIN;for(inti=0;i<leaves.size();i++){for(intj=i+1;j<leaves.size();j++){vector<Node*>path1,path2;findPath(root,leaves[i],path1);findPath(root,leaves[j],path2);intk=0;// Find the first different node in both paths.while(k<path1.size()&&k<path2.size()&&path1[k]==path2[k]){k++;}intsum=0;// Add the path from the LCA to the first leaf.for(intx=k-1;x<path1.size();x++)sum+=path1[x]->data;// Add the path from the LCA's child to the second leaf.for(intx=k;x<path2.size();x++)sum+=path2[x]->data;ans=max(ans,sum);}}returnans;}intmain(){Node*root=newNode(3);root->left=newNode(4);root->right=newNode(5);root->left->left=newNode(-10);root->left->right=newNode(4);cout<<maxPathSum(root);return0;}
Java
importjava.util.ArrayList;staticclassNode{intdata;Nodeleft,right;Node(intval){data=val;left=right=null;}}classGFG{staticbooleanfindPath(Noderoot,Nodetarget,ArrayList<Node>path){if(root==null)returnfalse;path.add(root);if(root==target)returntrue;if(findPath(root.left,target,path)||findPath(root.right,target,path))returntrue;path.remove(path.size()-1);returnfalse;}staticvoidcollectLeaves(Noderoot,ArrayList<Node>leaves){if(root==null)return;if(root.left==null&&root.right==null){leaves.add(root);return;}collectLeaves(root.left,leaves);collectLeaves(root.right,leaves);}staticintmaxPathSum(Noderoot){if(root==null)return-1;ArrayList<Node>leaves=newArrayList<>();collectLeaves(root,leaves);if(leaves.size()<2)return-1;intans=Integer.MIN_VALUE;for(inti=0;i<leaves.size();i++){for(intj=i+1;j<leaves.size();j++){ArrayList<Node>path1=newArrayList<>();ArrayList<Node>path2=newArrayList<>();findPath(root,leaves.get(i),path1);findPath(root,leaves.get(j),path2);intk=0;// Find the first different node in both// paths.while(k<path1.size()&&k<path2.size()&&path1.get(k)==path2.get(k)){k++;}intsum=0;for(intx=k-1;x<path1.size();x++)sum+=path1.get(x).data;for(intx=k;x<path2.size();x++)sum+=path2.get(x).data;ans=Math.max(ans,sum);}}returnans;}publicstaticvoidmain(String[]args){Noderoot=newNode(3);root.left=newNode(4);root.right=newNode(5);root.left.left=newNode(-10);root.left.right=newNode(4);System.out.println(maxPathSum(root));}}
Python
classNode:def__init__(self,data):self.data=dataself.left=Noneself.right=NonedeffindPath(root,target,path):ifrootisNone:returnFalsepath.append(root)ifrootistarget:returnTrueiffindPath(root.left,target,path)or \
findPath(root.right,target,path):returnTruepath.pop()returnFalsedefcollectLeaves(root,leaves):ifrootisNone:returnifroot.leftisNoneandroot.rightisNone:leaves.append(root)returncollectLeaves(root.left,leaves)collectLeaves(root.right,leaves)defmaxPathSum(root):ifrootisNone:return-1leaves=[]collectLeaves(root,leaves)iflen(leaves)<2:return-1ans=float('-inf')foriinrange(len(leaves)):forjinrange(i+1,len(leaves)):path1=[]path2=[]findPath(root,leaves[i],path1)findPath(root,leaves[j],path2)k=0# Find the first different node in both paths.whilek<len(path1)andk<len(path2)and \
path1[k]ispath2[k]:k+=1currentSum=0forxinrange(k-1,len(path1)):currentSum+=path1[x].dataforxinrange(k,len(path2)):currentSum+=path2[x].dataans=max(ans,currentSum)returnansif__name__=="__main__":root=Node(3)root.left=Node(4)root.right=Node(5)root.left.left=Node(-10)root.left.right=Node(4)print(maxPathSum(root))
C#
usingSystem;usingSystem.Collections.Generic;classNode{publicintdata;publicNodeleft;publicNoderight;publicNode(intval){data=val;left=right=null;}}classGFG{staticboolfindPath(Noderoot,Nodetarget,List<Node>path){if(root==null)returnfalse;path.Add(root);if(root==target)returntrue;if(findPath(root.left,target,path)||findPath(root.right,target,path))returntrue;path.RemoveAt(path.Count-1);returnfalse;}staticvoidcollectLeaves(Noderoot,List<Node>leaves){if(root==null)return;if(root.left==null&&root.right==null){leaves.Add(root);return;}collectLeaves(root.left,leaves);collectLeaves(root.right,leaves);}staticintmaxPathSum(Noderoot){if(root==null)return-1;List<Node>leaves=newList<Node>();collectLeaves(root,leaves);if(leaves.Count<2)return-1;intans=int.MinValue;for(inti=0;i<leaves.Count;i++){for(intj=i+1;j<leaves.Count;j++){List<Node>path1=newList<Node>();List<Node>path2=newList<Node>();findPath(root,leaves[i],path1);findPath(root,leaves[j],path2);intk=0;// Find the Lowest Common Ancestor.while(k<path1.Count&&k<path2.Count&&path1[k]==path2[k]){k++;}intsum=0;for(intx=k-1;x<path1.Count;x++)sum+=path1[x].data;for(intx=k;x<path2.Count;x++)sum+=path2[x].data;ans=Math.Max(ans,sum);}}returnans;}staticvoidMain(){Noderoot=newNode(3);root.left=newNode(4);root.right=newNode(5);root.left.left=newNode(-10);root.left.right=newNode(4);Console.WriteLine(maxPathSum(root));}}
JavaScript
// Finds the path from root to the target leaf.functionfindPath(root,target,path){if(root==null)returnfalse;path.push(root);if(root===target)returntrue;if(findPath(root.left,target,path)||findPath(root.right,target,path))returntrue;path.pop();returnfalse;}// Collects all leaf nodes of the tree.functioncollectLeaves(root,leaves){if(root==null)return;if(!root.left&&!root.right){leaves.push(root);return;}collectLeaves(root.left,leaves);collectLeaves(root.right,leaves);}functionmaxPathSum(root){if(root==null)return-1;letleaves=[];collectLeaves(root,leaves);if(leaves.length<2)return-1;letans=Number.MIN_SAFE_INTEGER;// Check every pair of leaf nodes.for(leti=0;i<leaves.length;i++){for(letj=i+1;j<leaves.length;j++){letpath1=[];letpath2=[];findPath(root,leaves[i],path1);findPath(root,leaves[j],path2);letk=0;// Find the Lowest Common Ancestor.while(k<path1.length&&k<path2.length&&path1[k]===path2[k]){k++;}letsum=0;// Add the path from LCA to the first leaf.for(letx=k-1;x<path1.length;x++)sum+=path1[x].key;// Add the path from LCA's child to the second leaf.for(letx=k;x<path2.length;x++)sum+=path2[x].key;ans=Math.max(ans,sum);}}returnans;}// Driver codefunctionNode(x){this.key=x;this.left=null;this.right=null;}letroot=newNode(3);root.left=newNode(4);root.right=newNode(5);root.left.left=newNode(-10);root.left.right=newNode(4);console.log(maxPathSum(root));
Output
16
[Expected Approach] Postorder DFS with Root-to-Leaf Path Sum - O(n) Time and O(h) Space
The idea is to use postorder traversal to find the maximum sum from each node down to a leaf. At every node with both left and right children, these two best root-to-leaf paths can be joined to form a leaf-to-leaf path through that node. We update the maximum answer with this path and return the better of the two paths to the parent.
Working of Approach:
Traverse the tree using postorder traversal, so both subtrees are processed before their parent.
For each node, calculate the maximum path sum from that node down to any leaf.
If the node has both children, combine their best sums with the current node's value and update the maximum leaf-to-leaf sum.
Return the larger root-to-leaf path sum from the two children to the parent.
If the node has only one child, continue through that child and return its path sum along with the current node's value.
If no valid path between two leaves exists, return -1.
Let us understand with an example: Input: root = [3, 4, 5, -10, 4, N, N]
Start with the leaf nodes -10, 4, and 5. Each leaf returns its own value.
At node 4, the left and right paths give -10 and 4. Their combined path is -10 + 4 + 4 = -2, while the best downward path is 4 + 4 = 8.
At node 3, the best paths from its left and right subtrees are 8 and 5. Combining them gives 8 + 3 + 5 = 16.
Therefore, the maximum leaf-to-leaf path is 4 -> 4 -> 3 -> 5, with a sum of 16.
C++
#include<bits/stdc++.h>usingnamespacestd;structNode{intdata;Node*left;Node*right;Node(intval){data=val;left=right=NULL;}};intmaxPathSumUtil(Node*root,int&res){if(root==NULL)return0;if(root->left==NULL&&root->right==NULL)returnroot->data;intleftSum=maxPathSumUtil(root->left,res);intrightSum=maxPathSumUtil(root->right,res);if(root->left&&root->right){// Combine both root-to-leaf paths through the current node.res=max(res,leftSum+rightSum+root->data);returnmax(leftSum,rightSum)+root->data;}if(root->left)returnleftSum+root->data;returnrightSum+root->data;}intmaxPathSum(Node*root){if(root==NULL)return-1;intres=INT_MIN;maxPathSumUtil(root,res);returnres==INT_MIN?-1:res;}intmain(){Node*root=newNode(3);root->left=newNode(4);root->right=newNode(5);root->left->left=newNode(-10);root->left->right=newNode(4);cout<<maxPathSum(root);return0;}
Java
classNode{intdata;Nodeleft,right;Node(intval){data=val;left=right=null;}}classGFG{staticintmaxPathSumUtil(Noderoot,int[]res){if(root==null)return0;if(root.left==null&&root.right==null)returnroot.data;intleftSum=maxPathSumUtil(root.left,res);intrightSum=maxPathSumUtil(root.right,res);if(root.left!=null&&root.right!=null){// Combine both root-to-leaf paths through the// current node.res[0]=Math.max(res[0],leftSum+rightSum+root.data);returnMath.max(leftSum,rightSum)+root.data;}if(root.left!=null)returnleftSum+root.data;returnrightSum+root.data;}staticintmaxPathSum(Noderoot){if(root==null)return-1;int[]res={Integer.MIN_VALUE};maxPathSumUtil(root,res);returnres[0]==Integer.MIN_VALUE?-1:res[0];}publicstaticvoidmain(String[]args){Noderoot=newNode(3);root.left=newNode(4);root.right=newNode(5);root.left.left=newNode(-10);root.left.right=newNode(4);System.out.println(maxPathSum(root));}}
Python
classNode:def__init__(self,data):self.data=dataself.left=Noneself.right=NonedefmaxPathSumUtil(root,res):ifrootisNone:return0ifroot.leftisNoneandroot.rightisNone:returnroot.dataleftSum=maxPathSumUtil(root.left,res)rightSum=maxPathSumUtil(root.right,res)ifroot.leftandroot.right:# Combine both root-to-leaf paths through the current node.res[0]=max(res[0],leftSum+rightSum+root.data)returnmax(leftSum,rightSum)+root.dataifroot.left:returnleftSum+root.datareturnrightSum+root.datadefmaxPathSum(root):ifrootisNone:return-1res=[float('-inf')]maxPathSumUtil(root,res)return-1ifres[0]==float('-inf')elseres[0]if__name__=="__main__":root=Node(3)root.left=Node(4)root.right=Node(5)root.left.left=Node(-10)root.left.right=Node(4)print(maxPathSum(root))
C#
usingSystem;classNode{publicintdata;publicNodeleft;publicNoderight;publicNode(intval){data=val;left=right=null;}}classGFG{staticintmaxPathSumUtil(Noderoot,refintres){if(root==null)return0;if(root.left==null&&root.right==null)returnroot.data;intleftSum=maxPathSumUtil(root.left,refres);intrightSum=maxPathSumUtil(root.right,refres);if(root.left!=null&&root.right!=null){// Combine both root-to-leaf paths through the// current node.res=Math.Max(res,leftSum+rightSum+root.data);returnMath.Max(leftSum,rightSum)+root.data;}if(root.left!=null)returnleftSum+root.data;returnrightSum+root.data;}staticintmaxPathSum(Noderoot){if(root==null)return-1;intres=int.MinValue;maxPathSumUtil(root,refres);returnres==int.MinValue?-1:res;}staticvoidMain(){Noderoot=newNode(3);root.left=newNode(4);root.right=newNode(5);root.left.left=newNode(-10);root.left.right=newNode(4);Console.WriteLine(maxPathSum(root));}}
JavaScript
// Returns the maximum root-to-leaf path sum.functionmaxPathSumUtil(root,res){if(root==null)return0;// Leaf nodeif(!root.left&&!root.right)returnroot.key;// Recur for left and right subtreesletls=maxPathSumUtil(root.left,res);letrs=maxPathSumUtil(root.right,res);// If both children exist, this node can connect two leavesif(root.left&&root.right){res[0]=Math.max(res[0],ls+rs+root.key);returnMath.max(ls,rs)+root.key;}// Return the path through the existing childif(root.left)returnls+root.key;returnrs+root.key;}functionmaxPathSum(root){if(root==null)return-1;letres=[Number.MIN_SAFE_INTEGER];maxPathSumUtil(root,res);// No path exists between two leaf nodes.returnres[0]===Number.MIN_SAFE_INTEGER?-1:res[0];}// Driver codefunctionNode(x){this.key=x;this.left=null;this.right=null;}letroot=newNode(3);root.left=newNode(4);root.right=newNode(5);root.left.left=newNode(-10);root.left.right=newNode(4);console.log(maxPathSum(root));