Algorithms

Maximum Path Sum

9 months ago ; 139 views
Share this

Problem

The problem this solution is trying to solve is to find the maximum path sum in a binary tree. The path starts and ends at any node in the tree, but it must follow parent-child connections and go downward.

Thought Process

Here's how this solution is arrived at.

Understanding the Problem
       

We need to find the maximum sum of a path in a binary tree. Keep in mind that the path starts and ends at any node. This problem can be efficiently solved using recursion by traversing the binary tree.

Identifying Key Components

 

  • We need to traverse the binary tree and calculate the maximum path sum for each node.
  • At each node, we need to consider three possibilities:
    • The maximum sum ends at the current node.
    • The maximum path sum in the left subtree.
    • The maximum path sum in the right subtree.
  • We also need to consider the possibility of an empty tree.

Developing the Solution

A recursive approach is essential in traversing the binary tree and calculating the maximum path sum for each node. For each node, we compute the maximum sum of a branch ending at the current node and the maximum path sum in the subtree rooted at the current node.

We have updated the maximum path sum encountered so far.

We continue this process recursively for the left and right subtrees until we reach the leaf nodes.

Handling Edge Cases

We need to handle the case of an empty tree by returning 0 as the maximum path sum.

Testing

We can test the solution with various test cases, including both balanced and unbalanced trees, to ensure it works correctly.

Solution: Maximum Path Sum Algorithm

# O(n) time | O(log(n)) space
class TreeNode:
    def __init__(self, value):
        """
        Initialize a TreeNode with a given value.

        Parameters:
        - value: The value of the TreeNode.
        """
        self.value = value
        self.left = None
        self.right = None

def maxPathSum(tree):
    """
    Finds the maximum path sum in a binary tree.

    Parameters:
    - tree: The root node of the binary tree.

    Returns:
    - The maximum path sum in the binary tree.
    """

    _, maxSum = findMaxSum(tree)
    return maxSum

def findMaxSum(tree):
    """
    Recursively finds the maximum path sum in a binary tree rooted at 'tree'.

    Parameters:
    - tree: The root node of the binary tree.

    Returns:
    - A tuple containing two elements:
      - The maximum sum of a branch ending at the current node.
      - The maximum path sum found in the subtree rooted at the current node.
    """
    if tree is None:
        # Base case: If the tree is empty, return (0, 0) indicating no sum.
        return (0, 0)

    # Recursively find the maximum sum in the left subtree.
    leftMaxSumAsBranch, leftMaxPathSum = findMaxSum(tree.left)
    
    # Recursively find the maximum sum in the right subtree.
    rightMaxSumAsBranch, rightMaxPathSum = findMaxSum(tree.right)
    
    # Determine the maximum sum of a branch considering the current node.
    maxChildSumAsBranch = max(leftMaxSumAsBranch, rightMaxSumAsBranch)
    value = tree.value
    maxSumAsBranch = max(maxChildSumAsBranch + value, value)
    
    # Determine the maximum path sum considering the current node as the root.
    maxSumAsRootNode = max(leftMaxSumAsBranch + value + rightMaxSumAsBranch, maxSumAsBranch)
    
    # Determine the maximum path sum considering the current node.
    maxPathSum = max(leftMaxPathSum, rightMaxPathSum, maxSumAsRootNode)

    # Return the maximum sum of a branch and the maximum path sum.
    return (maxSumAsBranch, maxPathSum)


# Create a binary tree from the given list [1, 2, 3, 4, 5, 6, 7]
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)
root.right.left = TreeNode(6)
root.right.right = TreeNode(7)

# Call maxPathSum function with the root of the tree
print(maxPathSum(root))

 

Time & Space Complexity

The time and space complexity of the provided solution can be analyzed as follows:

Time Complexity

Traversal

The algorithm traverses each node of the binary tree exactly once. Considering the N nodes in the binary tree (where N is the number of nodes), the time complexity of the traversal is O(N).

Recursion

At each node, the algorithm performs constant-time operations to compute the maximum sum. Since the recursion traverses each node once, the time complexity of the recursion is also O(N).

Overall, the max path sum algorithm's time complexity is O(N).

Space Complexity

Recursion

The space complexity of the recursion depends on the maximum depth of the recursion stack. On the off chance that the binary tree is skewed, then that's the worst-case scenario.

As a result, it leads to a recursion depth of N (the number of nodes). Therefore, the space complexity of the recursion is O(N).

Auxiliary Space

Apart from the recursion stack, the algorithm uses a constant amount of auxiliary space for variables such as leftMaxSumAsBranch, rightMaxSumAsBranch, etc. Therefore, the auxiliary space complexity is O(1).

Therefore, the overall space complexity of the solution is O(N) due to the recursion stack.

Unit Tests for Max Path Sum

Here are some unit tests for the provided solution using the unittest module:

In these tests:

  •     We define a TreeNode class within the setUp method to avoid repetition.
  •     We have test cases for an empty tree, a tree with a single node, a balanced tree, and an unbalanced tree to cover various scenarios.
  •     We use assertEqual to verify that the output of maxPathSum matches the expected maximum path sum for each tree.
import unittest

class TestMaxPathSum(unittest.TestCase):
    def setUp(self):
        # Define the TreeNode class
        class TreeNode:
            def __init__(self, value):
                self.value = value
                self.left = None
                self.right = None

        self.TreeNode = TreeNode

    def test_maxPathSum_emptyTree(self):
        root = None
        self.assertEqual(maxPathSum(root), 0)

    def test_maxPathSum_singleNode(self):
        root = self.TreeNode(5)
        self.assertEqual(maxPathSum(root), 5)

    def test_maxPathSum_balancedTree(self):
        # Construct a balanced binary tree
        root = self.TreeNode(1)
        root.left = self.TreeNode(2)
        root.right = self.TreeNode(3)
        root.left.left = self.TreeNode(4)
        root.left.right = self.TreeNode(5)
        root.right.left = self.TreeNode(6)
        root.right.right = self.TreeNode(7)
        self.assertEqual(maxPathSum(root), 18)  # Path: 5 -> 2 -> 1 -> 3 -> 7

    def test_maxPathSum_unbalancedTree(self):
        # Construct an unbalanced binary tree
        root = self.TreeNode(10)
        root.left = self.TreeNode(2)
        root.left.left = self.TreeNode(20)
        root.left.right = self.TreeNode(1)
        root.right = self.TreeNode(10)
        root.right.right = self.TreeNode(-25)
        root.right.right.left = self.TreeNode(3)
        root.right.right.right = self.TreeNode(4)
        self.assertEqual(maxPathSum(root), 42)  # Path: 20 -> 2 -> 10 -> 10 -> 3 -> 4

if __name__ == "__main__":
    unittest.main()

 

 

 

 

Become a member
Get the latest news right in your inbox. We never spam!

Read next

Island Perimeter

 This solution seeks to find the perimeter of an island in a grid.  The problem considers a grid where each cell represents land (1) or … Read More

Kibsoft 5 months, 3 weeks ago . 119 views

Pacific Atlantic Waterflow

5 months, 3 weeks ago . 119 views