DP on Trees Maximum Path Sum in DSA Python - Time & Space Complexity
We want to understand how the time needed to find the maximum path sum in a tree grows as the tree gets bigger.
How does the number of steps change when the tree has more nodes?
Analyze the time complexity of the following code snippet.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def maxPathSum(root):
max_sum = float('-inf')
def dfs(node):
nonlocal max_sum
if not node:
return 0
left = max(dfs(node.left), 0)
right = max(dfs(node.right), 0)
max_sum = max(max_sum, node.val + left + right)
return node.val + max(left, right)
dfs(root)
return max_sum
This code finds the maximum sum of values along any path in a binary tree using a depth-first search.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive depth-first search (dfs) visits each node once.
- How many times: Each node in the tree is visited exactly one time.
As the number of nodes in the tree increases, the number of steps grows roughly the same way.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 visits |
| 100 | About 100 visits |
| 1000 | About 1000 visits |
Pattern observation: The work grows linearly with the number of nodes.
Time Complexity: O(n)
This means the time to find the maximum path sum grows directly in proportion to the number of nodes in the tree.
[X] Wrong: "The recursion visits nodes multiple times, so the time is more than linear."
[OK] Correct: Each node is visited once, and results are combined on the way back, so no repeated work happens.
Understanding this helps you solve many tree problems efficiently by using recursion smartly without repeating work.
"What if the tree was very unbalanced, like a linked list? How would the time complexity change?"
Practice
Maximum path sum means:Solution
Step 1: Understand the path definition
A path in a tree is any sequence of nodes connected by edges, not necessarily starting at the root.Step 2: Define maximum path sum meaning
The maximum path sum is the highest sum of node values along any such path, which can start and end anywhere.Final Answer:
The largest sum of node values along any path between two nodes -> Option AQuick Check:
Maximum path sum = largest node value sum [OK]
- Confusing path sum with total tree sum
- Thinking path must start at root
- Considering only single nodes
def max_path_sum_helper(node: Optional[TreeNode]) -> int:
Solution
Step 1: Understand parameter type
The node can be None (empty), so Optional[TreeNode] is correct to allow None.Step 2: Understand return type
The helper returns an integer representing max path sum from that node, so return type is int.Final Answer:
def max_path_sum_helper(node: Optional[TreeNode]) -> int: -> Option CQuick Check:
Optional node input and int output [OK]
- Not allowing None as input node
- Returning wrong type like None or TreeNode
- Using wrong parameter types
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def max_path_sum(root):
max_sum = float('-inf')
def helper(node):
nonlocal max_sum
if not node:
return 0
left = max(helper(node.left), 0)
right = max(helper(node.right), 0)
max_sum = max(max_sum, node.val + left + right)
return node.val + max(left, right)
helper(root)
return max_sum
root = TreeNode(-10, TreeNode(9), TreeNode(20, TreeNode(15), TreeNode(7)))
print(max_path_sum(root))Solution
Step 1: Calculate max path sums for subtrees
Left subtree max path sum is 9. Right subtree max path sum includes 20 + 15 + 7 = 42.Step 2: Calculate max path sum including root
Root value is -10, so max path sum including root is max(9, 0) + -10 + max(35, 0) = 34, but max_sum is updated to 42 from right subtree.Final Answer:
42 -> Option BQuick Check:
Max path sum = 15+20+7 = 42 [OK]
- Adding negative paths instead of ignoring
- Confusing return value with max_sum
- Missing nonlocal max_sum update
def max_path_sum(root):
max_sum = float('-inf')
def helper(node):
if not node:
return 0
left = helper(node.left)
right = helper(node.right)
max_sum = max(max_sum, node.val + left + right)
return node.val + max(left, right)
helper(root)
return max_sumSolution
Step 1: Check variable scope of max_sum
max_sum is assigned inside helper but declared outside, so it needs 'nonlocal' to modify outer variable.Step 2: Understand effect of missing nonlocal
Without 'nonlocal', max_sum inside helper is local, so outer max_sum never updates, causing wrong result.Final Answer:
max_sum is not declared as nonlocal inside helper -> Option AQuick Check:
Use nonlocal to update outer max_sum [OK]
- Forgetting nonlocal keyword
- Returning max_sum inside helper incorrectly
- Ignoring base case for None nodes
Choose the best approach:
Solution
Step 1: Understand negative values impact
If all nodes are negative, the maximum path sum is the largest (least negative) single node value, since no path sums to 0 and longer paths sum to less.Step 2: Modify algorithm to track max single node
Keep track of the maximum node value separately and return it if all path sums are negative.Final Answer:
Return the maximum single node value if all sums are negative -> Option DQuick Check:
Handle all-negative by max single node value [OK]
- Returning 0 when all nodes are negative
- Adding absolute values incorrectly
- Restricting paths to root only
Ready to prove it?
Pass the test and this pattern moves unknown
