Given a binary tree root
, return the maximum sum of all keys of any sub-tree which is also a Binary Search Tree (BST).
Assume a BST is defined as follows:
Example 1:
Input: root = [1,4,3,2,4,2,5,null,null,null,null,null,null,4,6] Output: 20 Explanation: Maximum sum in a valid Binary search tree is obtained in root node with key equal to 3.
Example 2:
Input: root = [4,3,null,1,2] Output: 2 Explanation: Maximum sum in a valid Binary search tree is obtained in a single root node with key equal to 2.
Example 3:
Input: root = [-4,-2,-5] Output: 0 Explanation: All values are negatives. Return an empty BST.
Constraints:
[1, 4 * 104]
.-4 * 104 <= Node.val <= 4 * 104
This problem asks to find the maximum sum of nodes within a subtree that also forms a valid Binary Search Tree (BST). A simple traversal isn't sufficient because we need to simultaneously check for BST properties and track the maximum sum. The optimal solution uses Depth-First Search (DFS) with a clever return value from the recursive function.
The core idea is to perform a post-order DFS traversal. For each node, we recursively explore the left and right subtrees. The key is what information we return from the recursive calls: a 4-element tuple. This tuple efficiently summarizes the results of the subtree exploration:
bst
(boolean): Indicates whether the subtree rooted at the current node is a valid BST (true/false).min
(integer): The minimum value in the subtree.max
(integer): The maximum value in the subtree.sum
(integer): The sum of all node values in the subtree.The dfs
function works as follows:
Base Case (Leaf Node or null
): If the current node is null (empty subtree), it's considered a valid BST with min = ∞, max = -∞, and sum = 0.
Recursive Calls: Recursively calls dfs
on the left and right subtrees, obtaining their respective tuples.
BST Check and Update: A subtree rooted at the current node is a valid BST only if:
lbst
and rbst
are true).lmx < root.val
).root.val < rmi
).Sum Calculation: If the subtree is a valid BST, calculate its sum (s = ls + rs + root.val
). Update the global maximum sum (ans
) if necessary.
Return Value: Return a tuple containing (bst
, min
, max
, sum
). The min
and max
values are updated to reflect the minimum and maximum values of the current subtree.
class Solution:
def maxSumBST(self, root: Optional[TreeNode]) -> int:
self.ans = 0
inf = float('inf') # Use float('inf') for infinity
def dfs(node):
if not node:
return True, inf, -inf, 0
lbst, lmin, lmax, lsum = dfs(node.left)
rbst, rmin, rmax, rsum = dfs(node.right)
if lbst and rbst and lmax < node.val < rmin:
bst = True
min_val = min(node.val, lmin)
max_val = max(node.val, rmax)
sum_val = lsum + rsum + node.val
self.ans = max(self.ans, sum_val)
return bst, min_val, max_val, sum_val
else:
return False, 0, 0, 0 #Invalid BST
dfs(root)
return self.ans
The code in other languages (Java, C++, Go, TypeScript) follows the same logic, just with syntax variations for handling tuples/arrays and infinity. The essential structure of the dfs
function remains consistent across all languages.