Leetcode 98. Validate Binary Search Tree

Problem Explanation:

The problem asks us if a given binary tree is a valid Binary Search Tree (BST). A BST is a tree where each node has up to two children, and for each node, the left child's value is less than the node's value, and the right child's value is greater than the node's value.

This is best illustrated with an example:


Consider the binary tree:

1     2
2   / \
3  1   3

This is a valid BST because:

The root node has a value of 2. It's left child's value (1) is less than the root's value, and it's right child's value (3) is bigger than the root's value. Also, the subtrees satisfy the Binary Search Tree property. Hence, the output will be "true".

Our approach to solving this problem is to use recursion. We start from the root of the tree and, if necessary, assign a maximum and minimum possible value for each node. This ensures that all the nodes in the left are less than root and all the nodes in the right are greater than root.

Python Solution:

3class Node:
4    def __init__(self, x):
5        self.val = x
6        self.left = None
7        self.right = None
9class Solution:
10    def isValidBST(self, root):
11        def helper(node, lower=float('-inf'), upper=float('inf')):
12            if not node:
13                return True
14            val = node.val
15            if val <= lower or val >= upper:
16                return False
17            if not helper(node.right, val, upper):
18                return False
19            if not helper(node.left, lower, val):
20                return False
21            return True
23        return helper(root)

Java Solution:

The java solution will be similar to the python solution. Thus, it retains a similar structure while making changes for the Java syntax and language semantics.

3class Solution {
4    public boolean isValidBST(TreeNode root) {
5        return validate(root, Long.MIN_VALUE, Long.MAX_VALUE);
6    }
8    public boolean validate(TreeNode node, long min, long max){
9        if(node == null){
10            return true;
11        }
12        if(node.val <= min || node.val >= max){
13            return false;
14        }
15        return validate(node.left, min, node.val) && validate(node.right, node.val, max);
16    }

JavaScript Solution:

3var isValidBST = function(root, min=null, max=null) {
4    if(!root) return true;
5    if(min !== null && root.val <= min) return false;
6    if(max !== null && root.val >= max) return false;
7    return isValidBST(root.left, min, root.val) && isValidBST(root.right, root.val, max);    

C++ Solution:

3class Solution {
5    bool isValidBST(TreeNode* root, TreeNode* minNode = NULL, TreeNode* maxNode = NULL) {
6        if (root == NULL)
7            return true;
8        if (minNode != NULL && root->val <= minNode->val)
9            return false;
10        if (maxNode != NULL && root->val >= maxNode->val)
11            return false;
12        return isValidBST(root->left, minNode, root) && isValidBST(root->right, root, maxNode);
13    }

C# Solution:

3public class Solution {
4    public bool IsValidBST(TreeNode root) {
5        return Validate(root, long.MinValue, long.MaxValue);
6    }
8    private bool Validate(TreeNode node, long min, long max){
9        if(node == null){
10            return true;
11        }
12        if(node.val <= min || node.val >= max) {
13            return false;
14        }
15        return Validate(node.left, min, node.val) && Validate(node.right, node.val, max);
16    }

The Complexity Analysis

The time complexity for the solution in every programming language is O(N), where N is the number of nodes in the tree. This is because we visit each node exactly once.

The space complexity is also O(N). Although we don't explicitly use any additional data structures, we must take into account the memory required for the recursive calls. In the worst-case scenario of a skewed binary tree, the maximum depth of the tree is N, and since in each recursive call we add a new level to the system call stack, the maximum space needed (for the stack) would be proportional to N.

The presented solution is one of the most efficient ways to solve this problem considering both time and space complexity. However, it is worth noting that the design of the solution can be influenced by other factors, such as readability of the code, which can be especially important in more complex and larger codebases. In such cases, the most optimized code might not be the best solution, and trade-offs need to be considered. For this particular problem, the provided solutions strike a good balance between these aspects.

Finally, one more thing worth mentioning is that binary trees are a fundamental data structure in computer science, and proficiency with them is necessary for many algorithmic problems. Problems similar to this one are common in technical interviews, and mastering them can open the door to more complex tree-related topics such as AVL trees, Red-Black Trees, B-trees and tries.

By understanding the characteristics of different types of trees and the most common manipulations and operations on trees (such as traversal, insertion and removal of nodes), and by practising implementing these operations and algorithms from scratch, one can significantly improve their problem-solving skills and increase their chances of success in technical interviews.

Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.

TA 👨‍🏫