Before attempting this problem, you should be comfortable with:
Binary Tree Traversal - Understanding pre-order, in-order, and post-order traversal patterns
Binary Search Tree (BST) Validation - Knowing the BST property and how to verify if a tree is a valid BST
Recursion with Return Values - Returning multiple pieces of information (min, max, size) from recursive calls
Post-Order Traversal - Processing children before the parent to aggregate information bottom-up
1. Pre-Order Traversal
Intuition
The most direct approach is to check every subtree: if a subtree is a valid BST, count its nodes. To verify the BST property, we need to ensure that every node in the left subtree is smaller than the current node, and every node in the right subtree is larger. We do this by finding the maximum value in the left subtree and the minimum value in the right subtree, then comparing them against the current node.
Algorithm
For each node, check if its subtree is a valid BST:
Find the maximum value in the left subtree; it must be less than the current node's value.
Find the minimum value in the right subtree; it must be greater than the current node's value.
Recursively verify that both left and right subtrees are also valid BSTs.
If the current subtree is a valid BST, count and return the number of nodes.
Otherwise, recursively search the left and right subtrees and return the maximum size found.
classSolution:defis_valid_bst(self, root: Optional[TreeNode])->bool:"""Check if given tree is a valid Binary Search Tree."""# An empty tree is a valid Binary Search Tree.ifnot root:returnTrue# Find the max node in the left subtree of current node.
left_max = self.find_max(root.left)# If the left subtree has a node greater than or equal to the current node,# then it is not a valid Binary Search Tree.if left_max >= root.val:returnFalse# Find the min node in the right subtree of current node.
right_min = self.find_min(root.right)# If the right subtree has a value less than or equal to the current node,# then it is not a valid Binary Search Tree.if right_min <= root.val:returnFalse# If the left and right subtrees of current tree are also valid BST.# then the whole tree is a BST.return self.is_valid_bst(root.left)and self.is_valid_bst(root.right)deffind_max(self, root: Optional[TreeNode])->int:# Max node in a empty tree should be smaller than parent.ifnot root:returnfloat('-inf')# Check the maximum node from the current node, left and right subtree of the current tree.returnmax(root.val, self.find_max(root.left), self.find_max(root.right))deffind_min(self, root: Optional[TreeNode])->int:# Min node in a empty tree should be larger than parent.ifnot root:returnfloat('inf')# Check the minimum node from the current node, left and right subtree of the current treereturnmin(root.val, self.find_min(root.left), self.find_min(root.right))defcount_nodes(self, root: Optional[TreeNode])->int:ifnot root:return0# Add nodes in left and right subtree.# Add 1 and return total size.return1+ self.count_nodes(root.left)+ self.count_nodes(root.right)deflargestBSTSubtree(self, root: Optional[TreeNode])->int:ifnot root:return0# If current subtree is a validBST, its children will have smaller size BST.if self.is_valid_bst(root):return self.count_nodes(root)# Find BST in left and right subtrees of current nodes.returnmax(self.largestBSTSubtree(root.left), self.largestBSTSubtree(root.right))
classSolution{// Function to check if given tree is a valid Binary Search Tree or not.privatebooleanisValidBST(TreeNode root){// An empty tree is a valid Binary Search Tree.if(root ==null){returntrue;}// Find the max node in the left subtree of current node.int leftMax =findMax(root.left);// If the left subtree has a node greater than or equal to the current node,// then it is not a valid Binary Search Tree.if(leftMax >= root.val){returnfalse;}// Find the min node in the right subtree of current node.int rightMin =findMin(root.right);// If the right subtree has a value less than or equal to the current node,// then it is not a valid Binary Search Tree.if(rightMin <= root.val){returnfalse;}// If the left and right subtrees of current tree are also valid BST.// then the whole tree is a BST.if(isValidBST(root.left)&&isValidBST(root.right)){returntrue;}returnfalse;}privateintfindMax(TreeNode root){// Max node in a empty tree should be smaller than parent.if(root ==null){returnInteger.MIN_VALUE;}// Check the maximum node from the current node, left and right subtree of the current treereturnMath.max(Math.max(root.val,findMax(root.left)),findMax(root.right));}privateintfindMin(TreeNode root){// Min node in a empty tree should be larger than parent.if(root ==null){returnInteger.MAX_VALUE;}// Check the minimum node from the current node, left and right subtree of the current treereturnMath.min(Math.min(root.val,findMin(root.left)),findMin(root.right));}privateintcountNodes(TreeNode root){// Empty tree has 0 nodes.if(root ==null){return0;}// Add nodes in left and right subtree.// Add 1 and return total size.return1+countNodes(root.left)+countNodes(root.right);}publicintlargestBSTSubtree(TreeNode root){if(root ==null){return0;}// If current subtree is a validBST, its children will have smaller size BST.if(isValidBST(root)){returncountNodes(root);}// Find BST in left and right subtrees of current nodes.returnMath.max(largestBSTSubtree(root.left),largestBSTSubtree(root.right));}}
classSolution{public:// Function to check if given tree is a valid Binary Search Tree or not.boolisValidBST(TreeNode* root){// An empty tree is a valid Binary Search Tree.if(!root){returntrue;}// Find the max node in the left subtree of current node.int leftMax =findMax(root->left);// If the left subtree has a node greater than or equal to the current node,// then it is not a valid Binary Search Tree.if(leftMax >= root->val){returnfalse;}// Find the min node in the right subtree of current node.int rightMin =findMin(root->right);// If the right subtree has a value less than or equal to the current node,// then it is not a valid Binary Search Tree.if(rightMin <= root->val){returnfalse;}// If the left and right subtrees of current tree are also valid BST.// then the whole tree is a BST.if(isValidBST(root->left)&&isValidBST(root->right)){returntrue;}returnfalse;}intfindMax(TreeNode* root){// Max node in a empty tree should be smaller than parent.if(!root){return INT_MIN;}// Check the maximum node from the current node, left and right subtree of the current treereturnmax({ root->val,findMax(root->left),findMax(root->right)});}intfindMin(TreeNode* root){// Min node in a empty tree should be larger than parent.if(!root){return INT_MAX;}// Check the minimum node from the current node, left and right subtree of the current treereturnmin({ root->val,findMin(root->left),findMin(root->right)});}intcountNodes(TreeNode* root){// Empty tree has 0 nodes.if(!root){return0;}// Add nodes in left and right subtree.// Add 1 and return total size.return1+countNodes(root->left)+countNodes(root->right);}intlargestBSTSubtree(TreeNode* root){if(!root){return0;}// If current subtree is a validBST, its children will have smaller size BST.if(isValidBST(root)){returncountNodes(root);}// Find BST in left and right subtrees of current nodes.returnmax(largestBSTSubtree(root->right),largestBSTSubtree(root->left));}};
classSolution{/**
* @param {TreeNode} root
* @return {number}
*/largestBSTSubtree(root){if(!root){return0;}// If current subtree is a validBST, its children will have smaller size BST.if(this.isValidBST(root)){returnthis.countNodes(root);}// Find BST in left and right subtrees of current nodes.return Math.max(this.largestBSTSubtree(root.left),this.largestBSTSubtree(root.right));}// Function to check if given tree is a valid Binary Search Tree or not.isValidBST(root){// An empty tree is a valid Binary Search Tree.if(!root){returntrue;}// Find the max node in the left subtree of current node.let leftMax =this.findMax(root.left);// If the left subtree has a node greater than or equal to the current node,// then it is not a valid Binary Search Tree.if(leftMax >= root.val){returnfalse;}// Find the min node in the right subtree of current node.let rightMin =this.findMin(root.right);// If the right subtree has a value less than or equal to the current node,// then it is not a valid Binary Search Tree.if(rightMin <= root.val){returnfalse;}// If the left and right subtrees of current tree are also valid BST.// then the whole tree is a BST.if(this.isValidBST(root.left)&&this.isValidBST(root.right)){returntrue;}returnfalse;}findMax(root){// Max node in a empty tree should me smaller than parent.if(!root){return Number.MIN_SAFE_INTEGER;}// Check the maximum node from the current node, left and right subtree of the current treereturn Math.max(root.val,this.findMax(root.left),this.findMax(root.right));}findMin(root){// Min node in a empty tree should me larger than parent.if(!root){return Number.MAX_SAFE_INTEGER;}// Check the minimum node from the current node, left and right subtree of the current treereturn Math.min(root.val,this.findMin(root.left),this.findMin(root.right));}countNodes(root){// Empty tree has 0 nodes.if(!root){return0;}// Add nodes in left and right subtree.// Add 1 and return total size.return1+this.countNodes(root.left)+this.countNodes(root.right);}}
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/funclargestBSTSubtree(root *TreeNode)int{if root ==nil{return0}ifisValidBST(root){returncountNodes(root)}returnmax(largestBSTSubtree(root.Left),largestBSTSubtree(root.Right))}funcisValidBST(root *TreeNode)bool{if root ==nil{returntrue}
leftMax :=findMax(root.Left)if leftMax >= root.Val {returnfalse}
rightMin :=findMin(root.Right)if rightMin <= root.Val {returnfalse}returnisValidBST(root.Left)&&isValidBST(root.Right)}funcfindMax(root *TreeNode)int{if root ==nil{return math.MinInt32
}returnmax(root.Val,max(findMax(root.Left),findMax(root.Right)))}funcfindMin(root *TreeNode)int{if root ==nil{return math.MaxInt32
}returnmin(root.Val,min(findMin(root.Left),findMin(root.Right)))}funccountNodes(root *TreeNode)int{if root ==nil{return0}return1+countNodes(root.Left)+countNodes(root.Right)}
/**
* Example:
* var ti = TreeNode(5)
* var v = ti.`val`
* Definition for a binary tree node.
* class TreeNode(var `val`: Int) {
* var left: TreeNode? = null
* var right: TreeNode? = null
* }
*/class Solution {funlargestBSTSubtree(root: TreeNode?): Int {if(root ==null)return0if(isValidBST(root)){returncountNodes(root)}returnmaxOf(largestBSTSubtree(root.left),largestBSTSubtree(root.right))}privatefunisValidBST(root: TreeNode?): Boolean {if(root ==null)returntrueval leftMax =findMax(root.left)if(leftMax >= root.`val`)returnfalseval rightMin =findMin(root.right)if(rightMin <= root.`val`)returnfalsereturnisValidBST(root.left)&&isValidBST(root.right)}privatefunfindMax(root: TreeNode?): Int {if(root ==null)return Int.MIN_VALUE
returnmaxOf(root.`val`,maxOf(findMax(root.left),findMax(root.right)))}privatefunfindMin(root: TreeNode?): Int {if(root ==null)return Int.MAX_VALUE
returnminOf(root.`val`,minOf(findMin(root.left),findMin(root.right)))}privatefuncountNodes(root: TreeNode?): Int {if(root ==null)return0return1+countNodes(root.left)+countNodes(root.right)}}
/**
* Definition for a binary tree node.
* public class TreeNode {
* public var val: Int
* public var left: TreeNode?
* public var right: TreeNode?
* public init() { self.val = 0; self.left = nil; self.right = nil; }
* public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; }
* public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) {
* self.val = val
* self.left = left
* self.right = right
* }
* }
*/classSolution{funclargestBSTSubtree(_ root:TreeNode?)->Int{guardlet root = root else{return0}ifisValidBST(root){returncountNodes(root)}returnmax(largestBSTSubtree(root.left),largestBSTSubtree(root.right))}privatefuncisValidBST(_ root:TreeNode?)->Bool{guardlet root = root else{returntrue}let leftMax =findMax(root.left)if leftMax >= root.val {returnfalse}let rightMin =findMin(root.right)if rightMin <= root.val {returnfalse}returnisValidBST(root.left)&&isValidBST(root.right)}privatefuncfindMax(_ root:TreeNode?)->Int{guardlet root = root else{returnInt.min }returnmax(root.val,max(findMax(root.left),findMax(root.right)))}privatefuncfindMin(_ root:TreeNode?)->Int{guardlet root = root else{returnInt.max }returnmin(root.val,min(findMin(root.left),findMin(root.right)))}privatefunccountNodes(_ root:TreeNode?)->Int{guardlet root = root else{return0}return1+countNodes(root.left)+countNodes(root.right)}}
Time & Space Complexity
Time complexity: O(N3)
Space complexity: O(N)
The recursion call stack can take at most O(H) space; in the worst-case scenario, the height of the tree will equal N.
Where N and H are the number of nodes and the max height of the given tree respectively
2. Pre-Order Traversal Optimized
Intuition
Instead of finding the min/max of entire subtrees, we can validate the BST using in-order traversal. In a valid BST, an in-order traversal visits nodes in strictly increasing order. By tracking the previously visited node during the traversal, we can verify the BST property in a single pass through each subtree, which reduces redundant work.
Algorithm
For each node, validate the BST using in-order traversal:
Recursively validate the left subtree first.
Check that the current node's value is greater than the previous node's value.
Update the previous node to the current node.
Recursively validate the right subtree.
If the subtree is a valid BST, count and return its nodes.
Otherwise, search the left and right subtrees and return the maximum size found.
classSolution:defis_valid_bst(self, root: Optional[TreeNode])->bool:"""Check if given tree is a valid BST using in-order traversal."""# An empty tree is a valid Binary Search Tree.ifnot root:returnTrue# If left subtree is not a valid BST return false.ifnot self.is_valid_bst(root.left):returnFalse# If current node's value is not greater than the previous # node's value in the in-order traversal return false.if self.previous and self.previous.val >= root.val:returnFalse# Update previous node to current node.
self.previous = root
# If right subtree is not a valid BST return false.return self.is_valid_bst(root.right)# Count nodes in current tree.defcount_nodes(self, root: Optional[TreeNode])->int:ifnot root:return0# Add nodes in left and right subtree.# Add 1 and return total size.return1+ self.count_nodes(root.left)+ self.count_nodes(root.right)deflargestBSTSubtree(self, root: Optional[TreeNode])->int:ifnot root:return0# Previous node is initially null.
self.previous =None# If current subtree is a validBST, its children will have smaller size BST.if self.is_valid_bst(root):return self.count_nodes(root)# Find BST in left and right subtrees of current nodes.returnmax(self.largestBSTSubtree(root.left), self.largestBSTSubtree(root.right))
classSolution{// Track previous node while doing inorder traversal.privateTreeNode previous;// Function to check if given tree is a valid Binary Search Tree or not.privatebooleanisValidBST(TreeNode root){// An empty tree is a valid Binary Search Tree.if(root ==null){returntrue;}// If left subtree is not a valid BST return false.if(!isValidBST(root.left)){returnfalse;}// If current node's value is not greater than the previous // node's value in the in-order traversal return false.if(previous !=null&& previous.val >= root.val){returnfalse;}// Update previous node to current node.
previous = root;// If right subtree is not a valid BST return false.returnisValidBST(root.right);}privateintcountNodes(TreeNode root){if(root ==null){return0;}// Add nodes in left and right subtree.// Add 1 and return total size.return1+countNodes(root.left)+countNodes(root.right);}publicintlargestBSTSubtree(TreeNode root){if(root ==null){return0;}// Set previous node to NULL initially.
previous =null;// If current subtree is a validBST, its children will have smaller size BST.if(isValidBST(root)){returncountNodes(root);}// Find BST in left and right subtrees of current nodes.returnMath.max(largestBSTSubtree(root.left),largestBSTSubtree(root.right));}}
classSolution{public:// Track previous node while doing inorder traversal.
TreeNode* previous =NULL;// Function to check if given tree is a valid Binary Search Tree or not.boolisValidBST(TreeNode* root){// An empty tree is a valid Binary Search Tree.if(!root){returntrue;}// If left subtree is not a valid BST return false.if(!isValidBST(root->left)){returnfalse;}// If current node's value is not greater than the previous // node's value in the in-order traversal return false.if(previous && previous->val >= root->val){returnfalse;}// Update previous node to current node.
previous = root;// If right subtree is not a valid BST return false.returnisValidBST(root->right);}intcountNodes(TreeNode* root){if(!root){return0;}// Add nodes in left and right subtree.// Add 1 and return total size.return1+countNodes(root->left)+countNodes(root->right);}intlargestBSTSubtree(TreeNode* root){if(!root){return0;}// Set previous node to NULL initially.
previous =NULL;// If current subtree is a validBST, its children will have smaller size BST.if(isValidBST(root)){returncountNodes(root);}// Find BST in left and right subtrees of current nodes.returnmax(largestBSTSubtree(root->left),largestBSTSubtree(root->right));}};
classSolution{/**
* @param {TreeNode} root
* @return {number}
*/largestBSTSubtree(root){if(!root){return0;}// Set previous node to NULL initially.this.previous =null;// If current subtree is a validBST, its children will have smaller size BST.if(this.isValidBST(root)){returnthis.countNodes(root);}// Find BST in left and right subtrees of current nodes.return Math.max(this.largestBSTSubtree(root.left),this.largestBSTSubtree(root.right));}// Function to check if given tree is a valid Binary Search Tree or not.isValidBST(root){// An empty tree is a valid Binary Search Tree.if(!root){returntrue;}// If left subtree is not a valid BST return false.if(!this.isValidBST(root.left)){returnfalse;}// If current node's value is not greater than the previous// node's value in the in-order traversal return false.if(this.previous &&this.previous.val >= root.val){returnfalse;}// Update previous node to current node.this.previous = root;// If right subtree is not a valid BST return false.returnthis.isValidBST(root.right);}countNodes(root){if(!root){return0;}// Add nodes in left and right subtree.// Add 1 and return total size.return1+this.countNodes(root.left)+this.countNodes(root.right);}}
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/funclargestBSTSubtree(root *TreeNode)int{if root ==nil{return0}var previous *TreeNode
var isValidBST func(node *TreeNode)bool
isValidBST =func(node *TreeNode)bool{if node ==nil{returntrue}if!isValidBST(node.Left){returnfalse}if previous !=nil&& previous.Val >= node.Val {returnfalse}
previous = node
returnisValidBST(node.Right)}var countNodes func(node *TreeNode)int
countNodes =func(node *TreeNode)int{if node ==nil{return0}return1+countNodes(node.Left)+countNodes(node.Right)}
previous =nilifisValidBST(root){returncountNodes(root)}returnmax(largestBSTSubtree(root.Left),largestBSTSubtree(root.Right))}
/**
* Example:
* var ti = TreeNode(5)
* var v = ti.`val`
* Definition for a binary tree node.
* class TreeNode(var `val`: Int) {
* var left: TreeNode? = null
* var right: TreeNode? = null
* }
*/class Solution {privatevar previous: TreeNode?=nullfunlargestBSTSubtree(root: TreeNode?): Int {if(root ==null)return0
previous =nullif(isValidBST(root)){returncountNodes(root)}returnmaxOf(largestBSTSubtree(root.left),largestBSTSubtree(root.right))}privatefunisValidBST(root: TreeNode?): Boolean {if(root ==null)returntrueif(!isValidBST(root.left))returnfalseif(previous !=null&& previous!!.`val` >= root.`val`)returnfalse
previous = root
returnisValidBST(root.right)}privatefuncountNodes(root: TreeNode?): Int {if(root ==null)return0return1+countNodes(root.left)+countNodes(root.right)}}
/**
* Definition for a binary tree node.
* public class TreeNode {
* public var val: Int
* public var left: TreeNode?
* public var right: TreeNode?
* public init() { self.val = 0; self.left = nil; self.right = nil; }
* public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; }
* public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) {
* self.val = val
* self.left = left
* self.right = right
* }
* }
*/classSolution{privatevar previous:TreeNode?=nilfunclargestBSTSubtree(_ root:TreeNode?)->Int{guardlet root = root else{return0}
previous =nilifisValidBST(root){returncountNodes(root)}returnmax(largestBSTSubtree(root.left),largestBSTSubtree(root.right))}privatefuncisValidBST(_ root:TreeNode?)->Bool{guardlet root = root else{returntrue}if!isValidBST(root.left){returnfalse}iflet prev = previous, prev.val >= root.val {returnfalse}
previous = root
returnisValidBST(root.right)}privatefunccountNodes(_ root:TreeNode?)->Int{guardlet root = root else{return0}return1+countNodes(root.left)+countNodes(root.right)}}
Time & Space Complexity
Time complexity: O(N2)
Space complexity: O(N)
The recursion call stack can take at most O(H) space; in the worst-case scenario, the height of the tree will equal N.
Where N and H are the number of nodes and the max height of the given tree respectively
3. Post-Order Traversal
Intuition
The key insight is that we can determine if a subtree is a valid BST by looking at information from its children. If we process nodes bottom-up (post-order), each node can inherit the min/max values and sizes from its children. A node forms a valid BST if the maximum value in its left subtree is less than the node, and the minimum value in its right subtree is greater than the node. By returning both the valid range and size from each recursive call, we avoid redundant traversals.
Algorithm
Define a helper function that returns three values for each node: minimum value, maximum value, and the size of the largest BST in that subtree.
For an empty node, return values that indicate a valid empty BST (min = infinity, max = negative infinity, size = 0).
Recursively process left and right children first.
If the current node is greater than the left max and less than the right min:
The subtree rooted here is a valid BST.
Return updated min/max bounds and the combined size.
Otherwise, return invalid bounds (to prevent parent from being a valid BST) and the maximum size found so far.
# Each node will return min node value, max node value, sizeclassNodeValue:def__init__(self, min_node, max_node, max_size):
self.max_node = max_node
self.min_node = min_node
self.max_size = max_size
classSolution:deflargest_bst_subtree_helper(self, root):# An empty tree is a BST of size 0.ifnot root:return NodeValue(float('inf'),float('-inf'),0)# Get values from left and right subtree of current tree.
left = self.largest_bst_subtree_helper(root.left)
right = self.largest_bst_subtree_helper(root.right)# Current node is greater than max in left AND smaller than min in right, it is a BST.if left.max_node < root.val < right.min_node:# It is a BST.return NodeValue(min(root.val, left.min_node),max(root.val, right.max_node),
left.max_size + right.max_size +1)# Otherwise, return [-inf, inf] so that parent can't be valid BSTreturn NodeValue(float('-inf'),float('inf'),max(left.max_size, right.max_size))deflargestBSTSubtree(self, root: Optional[TreeNode])->int:return self.largest_bst_subtree_helper(root).max_size
// Each node will return min node value, max node value, max sizeclassNodeValue{publicint maxNode, minNode, maxSize;NodeValue(int minNode,int maxNode,int maxSize){this.maxNode = maxNode;this.minNode = minNode;this.maxSize = maxSize;}};classSolution{publicNodeValuelargestBSTSubtreeHelper(TreeNode root){// An empty tree is a BST of size 0.if(root ==null){returnnewNodeValue(Integer.MAX_VALUE,Integer.MIN_VALUE,0);}// Get values from left and right subtree of current tree.NodeValue left =largestBSTSubtreeHelper(root.left);NodeValue right =largestBSTSubtreeHelper(root.right);// Current node is greater than max in left AND smaller than min in right, it is a BST.if(left.maxNode < root.val && root.val < right.minNode){// It is a BST.returnnewNodeValue(Math.min(root.val, left.minNode),Math.max(root.val, right.maxNode),
left.maxSize + right.maxSize +1);}// Otherwise, return [-inf, inf] so that parent can't be valid BSTreturnnewNodeValue(Integer.MIN_VALUE,Integer.MAX_VALUE,Math.max(left.maxSize, right.maxSize));}publicintlargestBSTSubtree(TreeNode root){returnlargestBSTSubtreeHelper(root).maxSize;}}
// Each node will return min node value, max node value, max sizeclassNodeValue{public:int maxNode, minNode, maxSize;NodeValue(int minNode,int maxNode,int maxSize){this->maxNode = maxNode;this->minNode = minNode;this->maxSize = maxSize;}};classSolution{public:
NodeValue largestBSTSubtreeHelper(TreeNode* root){// An empty tree is a BST of size 0.if(!root){returnNodeValue(INT_MAX, INT_MIN,0);}// Get values from left and right subtree of current tree.auto left =largestBSTSubtreeHelper(root->left);auto right =largestBSTSubtreeHelper(root->right);// Current node is greater than max in left AND smaller than min in right, it is a BST.if(left.maxNode < root->val && root->val < right.minNode){// It is a BST.returnNodeValue(min(root->val, left.minNode),max(root->val, right.maxNode),
left.maxSize + right.maxSize +1);}// Otherwise, return [-inf, inf] so that parent can't be valid BSTreturnNodeValue(INT_MIN, INT_MAX,max(left.maxSize, right.maxSize));}intlargestBSTSubtree(TreeNode* root){returnlargestBSTSubtreeHelper(root).maxSize;}};
// Each node will return isBST, max node value, min node value, sizeclassNodeValue{constructor(minNode, maxNode, maxSize){this.maxNode = maxNode;this.minNode = minNode;this.maxSize = maxSize;}};classSolution{/**
* @param {TreeNode} root
* @return {number}
*/largestBSTSubtree(root){returnlargestBSTSubtreeHelper(root).maxSize;}largestBSTSubtreeHelper(root){// An empty tree is a BST of size 0.if(!root){returnnewNodeValue(Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER,0);}// Get values from left and right subtree of current tree.let left =largestBSTSubtreeHelper(root.left);let right =largestBSTSubtreeHelper(root.right);// Current node is greater than max in left AND smaller than min in right, it is a BST.if(left.maxNode < root.val && root.val < right.minNode){// It is a BST.returnnewNodeValue(Math.min(root.val, left.minNode), Math.max(root.val, right.maxNode),
left.maxSize + right.maxSize +1);}// Otherwise, return [-inf, inf] so that parent can't be valid BSTreturnnewNodeValue(Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER,
Math.max(left.maxSize, right.maxSize));}}
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/type NodeValue struct{
MinNode, MaxNode, MaxSize int}funclargestBSTSubtree(root *TreeNode)int{returnhelper(root).MaxSize
}funchelper(root *TreeNode) NodeValue {if root ==nil{return NodeValue{math.MaxInt32, math.MinInt32,0}}
left :=helper(root.Left)
right :=helper(root.Right)if left.MaxNode < root.Val && root.Val < right.MinNode {return NodeValue{min(root.Val, left.MinNode),max(root.Val, right.MaxNode),
left.MaxSize + right.MaxSize +1,}}return NodeValue{math.MinInt32, math.MaxInt32,max(left.MaxSize, right.MaxSize)}}
/**
* Example:
* var ti = TreeNode(5)
* var v = ti.`val`
* Definition for a binary tree node.
* class TreeNode(var `val`: Int) {
* var left: TreeNode? = null
* var right: TreeNode? = null
* }
*/dataclassNodeValue(val minNode: Int,val maxNode: Int,val maxSize: Int)class Solution {funlargestBSTSubtree(root: TreeNode?): Int {returnhelper(root).maxSize
}privatefunhelper(root: TreeNode?): NodeValue {if(root ==null){returnNodeValue(Int.MAX_VALUE, Int.MIN_VALUE,0)}val left =helper(root.left)val right =helper(root.right)if(left.maxNode < root.`val` && root.`val` < right.minNode){returnNodeValue(minOf(root.`val`, left.minNode),maxOf(root.`val`, right.maxNode),
left.maxSize + right.maxSize +1)}returnNodeValue(Int.MIN_VALUE, Int.MAX_VALUE,maxOf(left.maxSize, right.maxSize))}}
/**
* Definition for a binary tree node.
* public class TreeNode {
* public var val: Int
* public var left: TreeNode?
* public var right: TreeNode?
* public init() { self.val = 0; self.left = nil; self.right = nil; }
* public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; }
* public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) {
* self.val = val
* self.left = left
* self.right = right
* }
* }
*/structNodeValue{let minNode:Intlet maxNode:Intlet maxSize:Int}classSolution{funclargestBSTSubtree(_ root:TreeNode?)->Int{returnhelper(root).maxSize
}privatefunchelper(_ root:TreeNode?)->NodeValue{guardlet root = root else{returnNodeValue(minNode:Int.max, maxNode:Int.min, maxSize:0)}letleft=helper(root.left)letright=helper(root.right)ifleft.maxNode < root.val && root.val <right.minNode {returnNodeValue(
minNode:min(root.val,left.minNode),
maxNode:max(root.val,right.maxNode),
maxSize:left.maxSize +right.maxSize +1)}returnNodeValue(minNode:Int.min, maxNode:Int.max, maxSize:max(left.maxSize,right.maxSize))}}
Time & Space Complexity
Time complexity: O(N)
Space complexity: O(N)
The recursion call stack can take at most O(H) space; in the worst-case scenario, the height of the tree will equal N.
Where N and H are the number of nodes and the max height of the given tree respectively
Common Pitfalls
Only Checking Immediate Children Instead of Entire Subtrees
A subtree is a valid BST only if all nodes in the left subtree are smaller than the root and all nodes in the right subtree are larger. Checking only the immediate left and right children misses violations deeper in the tree. Always propagate min/max bounds through the entire subtree to validate correctly.
Confusing BST Validity with Binary Tree Structure
A binary tree where each node has at most two children is not automatically a BST. The BST property requires strict ordering across entire subtrees, not just parent-child relationships. Do not assume validity based on tree shape alone; always verify the ordering constraint.
Returning Wrong Size When Subtree Is Not a Valid BST
When a subtree fails the BST check, its size should not be counted as a valid BST. Instead, return the maximum size found in its left or right child subtrees. Mixing up the return values causes incorrect propagation and wrong final answers.