The idea behind this approach is based on the property of BSTs: an in-order traversal of a BST produces a sorted list of values in ascending order.
The traversal function recursively visits all nodes in the tree in in-order fashion (left, root, right) and adds their values to the inorder vector.
After the traversal, the isValidBST function checks if the inorder vector is sorted in strictly ascending order. If not, the tree is not a valid BST.
Complexity:
Time Complexity: The time complexity is , where is the number of nodes in the tree. This is because each node is visited exactly once to build the inorder vector, and then we iterate through the vector once to check if it is sorted.
Space Complexity: The space complexity is , mainly due to the space used by the inorder vector, which can potentially hold all node values in the tree. Additionally, the space complexity of the recursion stack in the worst case (a skewed tree) can be . In the best case (a balanced tree), it would be , but the dominant factor is the space for the inorder vector.
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */classSolution{private:// The traversal function checks if the subtree rooted at 'node' is a valid BST.booltraversal(TreeNode*node,TreeNode*minNode,TreeNode*maxNode){// Base case: An empty node is always a valid BST.if(!node)returntrue;// Check if the current node's value violates the BST properties.// If 'minNode' is not null and the current node's value is not greater than 'minNode',// then it's not a valid BST.if(minNode&&node->val<=minNode->val)returnfalse;// Similarly, if 'maxNode' is not null and the current node's value is not less than 'maxNode',// then it's not a valid BST.if(maxNode&&node->val>=maxNode->val)returnfalse;// Recursively check the left and right subtrees, updating the constraints.// For the left subtree, the current node becomes the new 'maxNode', and// for the right subtree, it becomes the new 'minNode'.returntraversal(node->left,minNode,node)&&traversal(node->right,node,maxNode);}public:// Public interface to start the BST validation from the root.boolisValidBST(TreeNode*root){// Initiate the traversal with null pointers for minNode and maxNode,// as the root has no constraints initially.returntraversal(root,nullptr,nullptr);}};
Time Complexity: The time complexity is , where is the number of nodes in the tree. This is because we visit each node exactly once during the traversal.
Space Complexity: The space complexity is , where is the height of the tree. This is due to the recursive stack used for DFS. In the worst case (a skewed tree), the height of the tree can be , leading to space complexity. In the best case (a balanced tree), it would be .
classSolution{private:TreeNode*pre=nullptr;// Pointer to keep track of the previously visited node in in-order traversal.public:boolisValidBST(TreeNode*root){if(!root)returntrue;// Base case: An empty tree is a valid BST.// Recursively check the left subtree.booll=isValidBST(root->left);// Check if the current node's value is greater than the previous node's value.if(pre&&pre->val>=root->val)returnfalse;pre=root;// Update 'pre' to the current node.// Recursively check the right subtree.boolr=isValidBST(root->right);// The tree is a valid BST if both left and right subtrees are valid BSTs.returnl&&r;}};
Idea and Algorithm:
Similar to an in-order traversal, this approach visits nodes in a left-root-right order.
The difference lies in how it uses the pre pointer to remember the last node visited (in the in-order sequence).
When visiting each node, it checks if its value is greater than the value of the pre node. If not, the BST property is violated, and it returns false.
After checking, it updates pre to the current node and then proceeds to the right subtree.
Finally, the tree is a valid BST if both the left and right subtree checks return true.
Complexity:
Time Complexity: The time complexity is , where is the number of nodes in the tree. Despite the recursive calls, each node is visited exactly once.
Space Complexity: The space complexity is , where is the height of the tree. This space is used by the recursion stack. In the worst case (a skewed tree), can be . In a balanced tree, would be . The pre pointer does not add significant space complexity, as it's just a single additional pointer.