LeetCode #1373 Hard

Maximum Sum BST in Binary Tree

Find the maximum sum of keys of any subtree that is itself a valid BST.

bstdfsdp
Open on LeetCode ↗
02

Intuition

Post-order: each node needs to know, from each child, whether that subtree is a BST plus its min, max, and sum. The node is a BST root iff left is a BST with max < node < right's min. Track the best BST sum seen anywhere.

How to spot this pattern

One postorder pass returning a four-part summary per subtree: is it a BST, its min, its max, its sum. A node forms a BST only if both children do and its value sits strictly between the left max and the right min. Bundling everything a parent needs into one return value avoids repeated subtree scans.

03

Approach

1

Return a 4-tuple upward

(isBST, min, max, sum). Nulls report (True, +∞, −∞, 0) so leaves compose cleanly.

2

Combine at each node

Valid iff both children valid and leftMax < val < rightMin. New tuple: (True, min(leftMin,val), max(rightMax,val), sums+val).

3

Record candidates

Every valid combination updates the global best (empty subtree counts as 0 — answer never negative).

04

Solution & live demo

1class Solution:
2 def maxSumBST(self, root):
3 self.best = 0
4 INF = float("inf")
5 def dfs(node):
6 if not node: return True, INF, -INF, 0
7 lb, lmin, lmax, lsum = dfs(node.left)
8 rb, rmin, rmax, rsum = dfs(node.right)
9 if lb and rb and lmax < node.val < rmin:
10 s = lsum + rsum + node.val
11 self.best = max(self.best, s)
12 return True, min(lmin, node.val), max(rmax, node.val), s
13 return False, 0, 0, 0
14 dfs(root)
15 return self.best
05

Common pitfalls

Validating each subtree independently

✗ Wrong
if isBST(node): best = max(best, sumTree(node))
✓ Right
lb, lmin, lmax, lsum = dfs(node.left)

Both helpers walk the whole subtree, so the total is O(n²) on a skewed tree. Returning the validity, bounds, and sum together means each node is visited once.

Comparing against the children's values instead of their extremes

✗ Wrong
if node.left.val < node.val < node.right.val:
✓ Right
if lb and rb and lmax < node.val < rmin:

The BST property constrains the entire subtree, not just the immediate children. A deep node in the left subtree may exceed the root while the direct child does not, and only the subtree maximum catches it.

Initialising the answer to negative infinity

✗ Wrong
self.best = float('-inf')
✓ Right
self.best = 0

An empty subtree is a valid BST with sum 0, so 0 is always achievable and the answer is never negative. Starting at −∞ returns a negative sum when every BST in the tree has one.

06

Edge cases

All negative keys

Best BST may be empty → answer 0 per problem statement.

Invalid parent, valid deep subtree

Invalidity propagates up, but the deep subtree's sum was already recorded.

07

Complexity

Time
O(n)
Space
O(h)
One post-order pass with tuples.