Floor and Ceil in BST in DSA Rust - Time & Space Complexity
We want to know how long it takes to find the floor or ceil value in a Binary Search Tree (BST).
How does the search time change as the tree grows bigger?
Analyze the time complexity of the following code snippet.
fn floor_in_bst(root: &Option>, key: i32) -> Option {
let mut res = None;
let mut current = root;
while let Some(node) = current {
if node.val == key {
return Some(node.val);
} else if node.val > key {
current = &node.left;
} else {
res = Some(node.val);
current = &node.right;
}
}
res
}
This code finds the floor value (largest value less than or equal to key) in a BST by traversing from root down.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Traversing down the tree nodes one by one.
- How many times: At most once per tree level, moving to left or right child each step.
As the tree grows taller, the search path length grows roughly with the tree height.
| Input Size (n) | Approx. Operations (steps down tree) |
|---|---|
| 10 | Up to 4 steps (if balanced) |
| 100 | Up to 7 steps (if balanced) |
| 1000 | Up to 10 steps (if balanced) |
Pattern observation: The number of steps grows slowly as the tree grows, roughly proportional to the tree height.
Time Complexity: O(h)
This means the search time depends on the tree height, which is the number of levels from root to leaf.
[X] Wrong: "Finding floor or ceil always takes O(n) time because we might check every node."
[OK] Correct: The BST property lets us skip large parts of the tree, so we only follow one path down, not all nodes.
Understanding how BST properties help reduce search time is a key skill. It shows you can use data structure features to write efficient code.
"What if the BST is not balanced but skewed like a linked list? How would the time complexity change?"
Practice
floor of a value in a Binary Search Tree (BST) represent?Solution
Step 1: Understand the definition of floor in BST
The floor of a value is the largest value in the BST that is less than or equal to the given value.Step 2: Compare with other options
The smallest value in the BST greater than or equal to the given value describes the ceil, not the floor. Options C and D are unrelated to floor.Final Answer:
The greatest value in the BST less than or equal to the given value -> Option CQuick Check:
Floor = greatest ≤ value [OK]
- Confusing floor with ceil
- Thinking floor is the smallest value
- Assuming floor is always the root
Solution
Step 1: Analyze Rust ownership and references
Using&Optionallows borrowing the BST root without taking ownership, which is common in tree traversal.Step 2: Check return type suitability
ReturningOption<i32>is correct because floor may not exist (None). Other options either take ownership or return plaini32which may cause errors.Final Answer:
fn floor(root: &Option, key: i32) -> Option<i32> -> Option BQuick Check:
Borrow root & return Option<i32> for floor [OK]
- Taking ownership of root causing move errors
- Returning plain i32 without Option for missing floor
- Using incorrect parameter types
15
/ \
10 20
/ \ \
8 12 25
Solution
Step 1: Locate floor for key 14 in BST
Floor is greatest value ≤ 14. Values ≤ 14 are 8, 10, 12. 15 and above are > 14.Step 2: Identify the greatest among candidates
Among 8, 10, 12, the greatest is 12.Final Answer:
12 -> Option AQuick Check:
Floor(14) = 12 [OK]
- Choosing 15 which is greater than key
- Confusing floor with ceil
- Picking 10 instead of 12
fn ceil(root: &Option, key: i32) -> Option<i32> {
match root {
None => None,
Some(node) => {
if node.val == key {
Some(node.val)
} else if node.val > key {
ceil(&node.left, key)
} else {
let right_ceil = ceil(&node.right, key);
if right_ceil.is_some() {
right_ceil
} else {
Some(node.val)
}
}
}
}
}
What is the bug in this code?Solution
Step 1: Recall correct ceil recursion logic
For ceil: when node.val < key recurse right subtree; when node.val > key, recurse left and return left_ceil or node.val.Step 2: Examine code branches
Code useselse if node.val > key { ceil(&node.left, key) }(go left when > key) and else (< key) recurse right or node.val. This matches floor logic: go left when > key, right when < key updating candidate.Step 3: Verify with trace
In Q3 BST, key=14: path 15(>14) → left 10(<14) → right 12(<14) → None → 12 → 12. Returns 12 (floor), not 15 (ceil).Final Answer:
It incorrectly returns floor instead of ceil -> Option DQuick Check:
Branches match floor logic [OK]
- Confusing floor and ceil logic
- Misreading recursion branches
- Assuming missing recursion where none exists
Solution
Step 1: Consider efficiency of traversals
Traversing twice (Traverse the BST twice: once for floor and once for ceil separately) doubles time. Converting to array (Convert BST to sorted array and use binary search twice) adds extra space and time. BFS (Use BFS traversal to find floor and ceil) is not suitable for ordered search.Step 2: Single traversal updating floor and ceil
During one recursion, compare node value with key and update floor if node.val ≤ key, update ceil if node.val ≥ key. This is efficient and uses BST properties.Final Answer:
Traverse the BST once, updating floor and ceil candidates during the same recursion -> Option AQuick Check:
One traversal updating floor & ceil is optimal [OK]
- Doing two separate traversals wasting time
- Using BFS ignoring BST order
- Converting BST to array unnecessarily
Ready to prove it?
Pass the test and this pattern moves unknown
