Validate if Tree is BST in DSA Rust - Time & Space Complexity
We want to know how long it takes to check if a tree follows the rules of a Binary Search Tree (BST).
The question is: how does the time needed grow as the tree gets bigger?
Analyze the time complexity of the following code snippet.
fn is_bst(node: &Option>, min: Option, max: Option) -> bool {
match node {
None => true,
Some(n) => {
if let Some(min_val) = min {
if n.val <= min_val { return false; }
}
if let Some(max_val) = max {
if n.val >= max_val { return false; }
}
is_bst(&n.left, min, Some(n.val)) && is_bst(&n.right, Some(n.val), max)
}
}
}
This code checks if a binary tree is a BST by visiting each node once and verifying its value fits the allowed range.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive visit of each node in the tree.
- How many times: Once per node, so total visits equal the number of nodes (n).
As the tree grows, the function checks each node once, so the work grows directly with the number of nodes.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 checks |
| 100 | About 100 checks |
| 1000 | About 1000 checks |
Pattern observation: The time grows linearly with the number of nodes.
Time Complexity: O(n)
This means the time to check the tree grows directly in proportion to the number of nodes.
[X] Wrong: "Checking if a tree is a BST only needs to look at the root or a few nodes."
[OK] Correct: Every node must be checked to ensure it fits the BST rules, so skipping nodes can miss violations.
Understanding this time complexity helps you explain how efficient your tree checks are, a common skill in coding interviews.
"What if we used an in-order traversal to check the BST property instead? How would the time complexity change?"
Practice
Solution
Step 1: Understand BST property
A BST requires that for each node, all values in the left subtree are less than the node's value, and all values in the right subtree are greater.Step 2: Compare options with definition
Every node's left subtree contains only nodes with values less than the node's value, and the right subtree only nodes with values greater. correctly states this property, while others describe different tree properties.Final Answer:
Every node's left subtree contains only nodes with values less than the node's value, and the right subtree only nodes with values greater. -> Option AQuick Check:
BST property = Every node's left subtree contains only nodes with values less than the node's value, and the right subtree only nodes with values greater. [OK]
- Confusing BST with balanced tree
- Thinking all nodes must have two children
- Assuming all values are equal
Solution
Step 1: Understand Rust tree node usage
Binary trees in Rust are often represented as Option to allow for empty nodes and heap allocation.Step 2: Check function signature return type
The function should return a boolean indicating if the tree is a BST, so return type bool is correct.Final Answer:
fn is_bst(root: &Option) -> bool -> Option CQuick Check:
Correct Rust signature = fn is_bst(root: &Option) -> bool [OK]
- Using TreeNode directly without Option or Box
- Returning wrong type like i32 or String
- Not using reference for input parameter
struct TreeNode {
val: i32,
left: Option,
right: Option,
}
fn is_bst(node: &Option, min: Option<i32>, max: Option<i32>) -> bool {
match node {
None => true,
Some(n) => {
if let Some(min_val) = min {
if n.val <= min_val { return false; }
}
if let Some(max_val) = max {
if n.val >= max_val { return false; }
}
is_bst(&n.left, min, Some(n.val)) && is_bst(&n.right, Some(n.val), max)
}
}
}
fn main() {
let root = Some(Box::new(TreeNode {
val: 10,
left: Some(Box::new(TreeNode { val: 5, left: None, right: None })),
right: Some(Box::new(TreeNode { val: 15, left: None, right: None })),
}));
println!("{}", is_bst(&root, None, None));
}Solution
Step 1: Analyze tree structure
The root node is 10, left child 5, right child 15. This satisfies BST property: 5 < 10 < 15.Step 2: Trace is_bst function calls
Function checks node values against min and max bounds recursively. All nodes satisfy constraints, so returns true.Final Answer:
true -> Option AQuick Check:
Tree is BST = true [OK]
- Ignoring min/max bounds in recursion
- Confusing <= and < in comparisons
- Assuming tree is not BST without checking children
fn is_bst(node: &Option, min: Option<i32>, max: Option<i32>) -> bool {
match node {
None => true,
Some(n) => {
if let Some(min_val) = min {
if n.val < min_val { return false; }
}
if let Some(max_val) = max {
if n.val > max_val { return false; }
}
is_bst(&n.left, min, Some(n.val)) && is_bst(&n.right, Some(n.val), max)
}
}
}Solution
Step 1: Review comparison operators in BST validation
BST requires node values to be strictly greater than min and strictly less than max, so using < and > is incorrect for duplicates.Step 2: Correct comparison operators
Comparisons should be <= min_val and >= max_val to reject equal values and maintain BST property.Final Answer:
The comparisons should use <= and >= instead of < and > -> Option BQuick Check:
Use <= and >= for BST checks [OK]
- Using < and > allows duplicates breaking BST
- Mixing up parameter order in recursion
- Ignoring None case for empty trees
Solution
Step 1: Understand BST with duplicates on right
Duplicates allowed only on right means left subtree nodes must be strictly less than current node, right subtree nodes can be equal or greater.Step 2: Adjust min and max comparisons accordingly
For left subtree, use n.val < max_val (strict less), for right subtree use n.val >= min_val (allow equal or greater).Final Answer:
Allow equal values only on the right by using n.val >= min_val for right subtree and n.val < max_val for left subtree -> Option DQuick Check:
Duplicates right subtree = n.val >= min_val [OK]
- Allowing duplicates on left subtree
- Using <= for left subtree allowing duplicates
- Not adjusting comparisons for duplicates
Ready to prove it?
Pass the test and this pattern moves unknown
