Binary Tree Maximum Path Sum

Updated on 12 May, 2025
Binary Tree Maximum Path Sum header image

Problem Statement

In this problem, you are provided with the root of a binary tree. The task is to determine the maximum sum of values found on any path within this tree. A path is defined here as a sequence of nodes connected directly by edges, and uniquely, any given node can be used at most once in any path. Additionally, the path you consider does not necessarily need to start or end at the root of the tree. You need to calculate the sum of the node values for various possible paths and return the highest sum from among them.

Examples

Example 1

Input:

root = [1,2,3]

Output:

6

Explanation:

The optimal path is 2 -> 1 -> 3 with a path sum of 2 + 1 + 3 = 6.

Example 2

Input:

root = [-10,9,20,null,null,15,7]

Output:

42

Explanation:

The optimal path is 15 -> 20 -> 7 with a path sum of 15 + 20 + 7 = 42.

Constraints

  • The number of nodes in the tree is in the range [1, 3 * 104].
  • -1000 <= Node.val <= 1000

Approach and Intuition

  1. The primary challenge of this problem is to determine the maximum sum path that can start and end at any node, not being restricted to paths crossing the tree's root. Each node offers two main possibilities:

    • It serves as a turning point in the path, implying that the path could span from one of its children, through itself, reaching possibly into the other child.
    • It acts merely as part of a longer path that disregards this node as a junction.
  2. Recursion is a natural approach here:

    • At each node, calculate the maximum path sum for paths that pass through but do not necessarily end at that node.
    • This involves considering the node's value itself and the maximum sums of paths extending from either of its children (these paths would naturally extend only downwards).
  3. Implementing the recursive function:

    • For each node, determine the maximum contributions from the left and right children separately.
    • Calculate the value for the path passing through the node by taking its value and adding the positive contributions from both sides.
    • Update the global maximum path sum at each step if this new sum is larger.
  4. The recursive function will return the maximum sum of paths that can extend from a given node to its parent node. This means, for any node, it returns the maximum of:

    • The node's value alone (considering paths that might just start and end at this node).
    • The node's value plus the maximum extension either left or right, whichever is greater (for paths that extend upward through this node).
  5. Use a helper function that recursively carries out these steps, updating a global or externally scoped variable that tracks the maximum found at any node.

By following this recursive approach, you make sure every possible path's sum is calculated without repetitive processing, due to the nature of recursion which inherently covers all nodes and paths. This approach systematically and efficiently find the maximum path sum in the given binary tree.

Solutions

  • C++
  • Java
  • C
  • JavaScript
  • Python
cpp
class Solution {
public:
    int findMaxPath(TreeNode* node) {
        highestSum = INT_MIN;
        calculateMaxSubtreeSum(node);
        return highestSum;
    }

private:
    int highestSum;
    int calculateMaxSubtreeSum(TreeNode* node) {
        if (node == nullptr) {
            return 0;
        }
        int leftMax = max(calculateMaxSubtreeSum(node->left), 0);
        int rightMax = max(calculateMaxSubtreeSum(node->right), 0);
        highestSum = max(highestSum, leftMax + rightMax + node->val);
        return max(leftMax + node->val, rightMax + node->val);
    }
};

The solution involves calculating the maximum path sum in a binary tree where the path may start and end at any node. This is done using a C++ class named Solution with a recursive helper function.

  • The class has two primary components:
    • findMaxPath(TreeNode* node) - Public member function that initializes the highestSum to the smallest integer possible using INT_MIN. It then calls the recursive helper function calculateMaxSubtreeSum(node) and returns the maximum path sum found.

    • calculateMaxSubtreeSum(TreeNode* node) - Private member function that recursively calculates the maximum sum of any path in the subtree rooted at the provided node. It returns the maximum path sum that includes the current node at its top:

      • Base Case: If the node is null, it returns 0, since an empty tree has a path sum of 0.
      • Recursive Case: The function calculates the maximum path sums of the left and right child subtrees. It ensures that negative path sums do not decrease the overall maximum path sum by using the max function with 0.
      • The function updates highestSum to the maximum of its current value or the sum of the node's value and the maximum path sums from both child subtrees.
      • It returns the maximum value between the node's value plus either the left or right subtree's maximum sum, ensuring the continuation of the potential maximum path towards the parent node.

Through these functions, the solution efficiently finds the maximum path sum by avoiding paths that would decrease the sum due to negative values and continuously keeping track of the highest sum found during the recursion.

java
class Solution {
    public int maximumPathSum(TreeNode node) {
        highestSum = Integer.MIN_VALUE;
        sumFromNode(node);
        return highestSum;
    }

    private int highestSum;

    private int sumFromNode(TreeNode node) {
        if (node == null) {
            return 0;
        }

        int leftGain = Math.max(sumFromNode(node.left), 0);
        int rightGain = Math.max(sumFromNode(node.right), 0);

        highestSum = Math.max(highestSum, leftGain + rightGain + node.val);

        return Math.max(leftGain + node.val, rightGain + node.val);
    }
}

The given Java solution tackles the problem of finding the maximum path sum in a binary tree. In this problem, a path is defined as a sequence of nodes where each successive node is directly connected. Notably, the path doesn't need to pass through the root, and it can start and end at any node.

Review this breakdown to understand the structure and function of the code:

  • The maximumPathSum(TreeNode node) method serves as the entry point and initializes highestSum with the smallest integer value. It calls sumFromNode(node) to compute the highest path sum possible and returns this value.

  • highestSum is a private instance variable used to store the maximum path sum found during the traversal of the tree.

  • The recursive method sumFromNode(TreeNode node) calculates the maximum gain from either side of the given node and uses zero as a lower bound to ignore negative path sums. It calculates the potential maximum path sum including both children and the current node's value, updating highestSum if this sum is greater than any previously found.

  • The calculation for return value in sumFromNode ensures that for each node processed, the maximum sum involving either the left child or the right child (whichever is greater) plus the node's own value is returned. This aids in propagating the maximum gain up to the caller (either another recursive call or the initial call from maximumPathSum).

Remember, for optimal tree traversal performance and memory use, the implementation effectively utilizes recursion, with each call evaluating node contributions from the bottom of the tree upwards. This ensures that each node's maximum gain in context of its available children is considered, leading to an accurate global maximum across all evaluated paths.

c
int maximum(int x, int y) { return (x > y) ? x : y; }
int calculateGain(struct TreeNode* node, int* highestSum) {
    if (node == NULL) return 0;
    int leftGain = maximum(0, calculateGain(node->left, highestSum));
    int rightGain = maximum(0, calculateGain(node->right, highestSum));
    *highestSum = maximum(*highestSum, leftGain + rightGain + node->val);
    return maximum(leftGain + node->val, rightGain + node->val);
}
int findMaxPathSum(struct TreeNode* node) {
    int maxResult = INT_MIN;
    calculateGain(node, &maxResult);
    return maxResult;
}

The provided solution in C addresses a common problem in binary tree data structures: finding the maximum path sum. The maximum path sum is the highest sum of node values starting from any node and ending at any node in the tree, where the path doesn't need to pass through the root.

Overview of the Code Structure:

  • The maximum function is a straightforward utility to find the maximum of two integers.
  • The calculateGain function recursively traverses the binary tree. It calculates maximum path sums from the leaf towards the root, ensuring at each step that negative path sums are not considered (by comparing with 0). This function also updates the maximum path sum found during the traversal.
  • The main function, findMaxPathSum, initializes a variable to store the maximum result found, invokes calculateGain, and then returns the maximum path sum.

How the Code Works:

  1. Start with defining the maximum function to compare any two integers and return the greater value.
  2. Develop the calculateGain function to:
    • Return 0 if the current tree node is NULL, ensuring the termination of recursion.
    • Recursively find the maximum sum for both left and right subtrees. The recursion ensures that every node in the tree is considered.
    • Avoid accumulating negative sums by using the maximum function compared with 0.
    • Update the highest sum recorded using another call to maximum that includes the current node's value and the best gains from left and right subtrees.
    • Resolve the maximum path sum for the sub-tree with the current node as the root.
  3. Finally, implement the findMaxPathSum which initializes the maximum result as the smallest integer and starts the recursive calculation.

Conclusion:

This code efficiently calculates the maximum path sum in a binary tree by leveraging a helper function that uses recursive depth-first traversal. It ensures that only paths with positive contributions are considered, maximizing the computed path sum using local comparisons at each node, and updating a global sum that tracks the highest value found across all paths. This method efficiently handles the complexities of varying tree structures and data distributions.

js
function calculateMaxSum(root) {
    let maximumSum = -Infinity;

    function computeMaxGainLeftRight(node) {
        if (!node) return 0;

        let leftGain = Math.max(computeMaxGainLeftRight(node.left), 0);
        let rightGain = Math.max(computeMaxGainLeftRight(node.right), 0);

        maximumSum = Math.max(maximumSum, leftGain + rightGain + node.val);

        return Math.max(leftGain + node.val, rightGain + node.val);
    }
    computeMaxGainLeftRight(root);
    return maximumSum;
}

The provided JavaScript solution is designed to find the maximum path sum in a binary tree. The path may start and end at any node. In this implementation:

  • The calculateMaxSum function is the main function where the computation starts. It initializes maximumSum to negative infinity to handle cases where the tree contains all negative values.

  • Inside the main function, a nested helper function computeMaxGainLeftRight is declared. This recursive function is responsible for exploring each node of the binary tree and calculating the gain from each subtree that maximizes the path value using only one side of it (either left or right).

  • The recursion evaluates the left and right side gains of each node. The maximum gain for each side is calculated as the maximum value between the recursive call for that side and zero. This ensures that only positive contributions to the sum are considered.

  • The maximum path sum that passes through the node and includes both left and right children contributions is updated in maximumSum if it proves to be larger than the current maximumSum.

  • The recursion returns the maximum gain including the current node's value plus either the left or right maximum gain, whichever is larger. This value represents the maximum sum from the subtree rooted at the current node that can be included in some larger path.

  • After recursion completes on root, the calculateMaxSum function returns the maximumSum, which gives the maximum path sum found in the binary tree.

Use this function by calling calculateMaxSum with the tree's root node as an argument, and it will return the maximum path sum.

python
class Solution:
    def findMaxSum(self, root: Optional[TreeNode]) -> int:
        maximumPathSum = -float("inf")

        def calculateMaxGain(node: Optional[TreeNode]) -> int:
            nonlocal maximumPathSum

            if not node:
                return 0

            leftGain = max(calculateMaxGain(node.left), 0)
            rightGain = max(calculateMaxGain(node.right), 0)

            maximumPathSum = max(maximumPathSum, leftGain + rightGain + node.val)

            return max(leftGain + node.val, rightGain + node.val)

        calculateMaxGain(root)
        return maximumPathSum

The solution finds the maximum path sum in a binary tree, where a path is defined as any sequence of nodes from any starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root.

  • The problem is implemented in Python using a class named Solution with a function findMaxSum.
  • This function accepts a root of the binary tree and returns an integer representing the maximum path sum.
  • The main logic utilizes a helper function calculateMaxGain defined inside findMaxSum.
  • The helper function calculates the maximum gain from any node, which is the maximum sum of the node's value and the maximum path sums from its left and right children that do not form a fork (i.e., paths that start at the node and go downwards).
  • For each node, it considers two scenarios:
    1. The node is the highest point of the fork in the path, combining the maximum gains from both children and the node's value.
    2. The node is part of a linear path, continuing from either its left or right child.
  • Keep track of the global maximum path sum using a nonlocal variable maximumPathSum, updating it with the computed path sums from both scenarios.
  • If a node is None, it contributes 0 to the path sum (base case for recursion).
  • The function initiates the recursive computation with the root and returns the maximum path sum recorded.

Essentially, the algorithm efficiently calculates and updates the potential maximum sums at each node in a bottom-up manner, ensuring the maximum sum for any path configuration involving partial or full paths through nodes is captured. This recursive dynamic approach guarantees that all potential high-sum configurations are evaluated without redundant calculations, leveraging the benefits of avoiding negative contributions through the use of max(calculateMaxGain(node.left), 0) and similar constructions for right children.

Comments

No comments yet.