Given a root of binary search tree and a key(node) value, find the floor and ceil value for that particular key value.
If a particular floor or ceil value is not present then output -1.
Input : root = [8, 4, 12, 2, 6, 10, 14] , key = 11
Output : [10, 12]
Explanation :
Input : root = [8, 4, 12, 2, 6, 10, 14] , key = 15
Output : [14, -1]
Explanation :
Input : root = [8, 4, 12, 2, 6, 10, 14] , key = 1
Finding the floor value in a Binary Search Tree (BST) involves tracking the largest node value that is smaller than or equal to the given key. The thought process here is to either find the exact key or reach nodes close to the key’s value. During traversal, if the key matches the node’s value, this value is assigned as the floor, and the search concludes. If the key is smaller than the current node’s value, the algorithm moves to the left subtree to find a smaller value. If the key is larger, the algorithm updates the floor with the current node’s value and explores the right subtree for potentially larger values.
floor
to -1 to store the floor value initially.floor
with the current node’s value and move to the right subtree.floor
value if the key is not found in the tree. This floor
value represents the largest node value smaller than the key, or -1 if no such value exists in the BST.#include <bits/stdc++.h>
using namespace std;
// Definition for a binary tree node.
class TreeNode {
public:
int data;
TreeNode *left;
TreeNode *right;
TreeNode(int val) : data(val), left(nullptr), right(nullptr) {}
};
class Solution {
public:
vector<int> floorCeilOfBST(TreeNode* root, int key) {
// Initialize the floor and ceil values
int floor = -1;
int ceil = -1;
// Find the floor value
// Start from the root of the BST
TreeNode* current = root;
while (current) {
// If the key matches the current node's value
if (current->data == key) {
// Set floor to this value
floor = current->data;
break;
/* If the key is greater than the current node's value
Update floor to the current node's value
If the key is smaller than the current node's value
Move to the left subtree to find a smaller value */
} else if (current->data < key) {
floor = current->data;
current = current->right;
} else {
current = current->left;
}
}
// Find the ceil value
// Reset current to start from the root again
current = root;
while (current) {
// If the key matches the current node's value
if (current->data == key) {
// Set ceil to this value
ceil = current->data;
break;
/* If the key is smaller than the current node's value
Update ceil to the current node's value
If the key is greater than the current node's value
Move to the right subtree to find a larger value */
} else if (current->data > key) {
ceil = current->data;
current = current->left;
} else {
current = current->right;
}
}
// Return the floor and ceil values as a vector
return {floor, ceil};
}
};
// Utility function to insert a new node with given key in BST
TreeNode* insert(TreeNode* node, int key) {
if (node == nullptr) return new TreeNode(key);
if (key < node->data)
node->left = insert(node->left, key);
else if (key > node->data)
node->right = insert(node->right, key);
return node;
}
int main() {
// Create the BST
TreeNode* root = nullptr;
root = insert(root, 8);
insert(root, 4);
insert(root, 12);
insert(root, 2);
insert(root, 6);
insert(root, 10);
insert(root, 14);
// Key value to find floor and ceil for
int key = 11;
// Solution instance
Solution sol;
vector<int> result = sol.floorCeilOfBST(root, key);
// Output the floor and ceil values
cout << "Floor: " << result[0] << ", Ceil: " << result[1] << endl;
return 0;
}
import java.util.*;
class TreeNode {
int data;
TreeNode left, right;
TreeNode(int val) {
data = val;
left = right = null;
}
}
class Solution {
public List<Integer> floorCeilOfBST(TreeNode root, int key) {
// Initialize floor and ceil values to -1, indicating not found
int floor = -1;
int ceil = -1;
// Find the floor value
// Start from the root of the BST
TreeNode current = root;
while (current != null) {
// If the key matches the current node's value
if (current.data == key) {
// Set floor to this value
floor = current.data;
break;
/* If the key is greater than the current node's value
Update floor to the current node's value
If the key is smaller than the current node's value
Move to the left subtree to find a smaller value */
} else if (current.data < key) {
floor = current.data;
current = current.right;
} else {
current = current.left;
}
}
// Find the ceil value
// Reset current to start from the root again
current = root;
while (current != null) {
// If the key matches the current node's value
if (current.data == key) {
// Set ceil to this value
ceil = current.data;
break;
/* If the key is smaller than the current node's value
Update ceil to the current node's value
If the key is greater than the current node's value
Move to the right subtree to find a larger value */
} else if (current.data > key) {
ceil = current.data;
current = current.left;
} else {
current = current.right;
}
}
// Return floor and ceil values as a list
return Arrays.asList(floor, ceil);
}
public static void main(String[] args) {
// Creating a sample BST
TreeNode root = new TreeNode(8);
root.left = new TreeNode(4);
root.right = new TreeNode(12);
root.left.left = new TreeNode(2);
root.left.right = new TreeNode(6);
root.right.left = new TreeNode(10);
root.right.right = new TreeNode(14);
Solution sol = new Solution();
int key = 11; // Key to find floor and ceil for
// Find and print floor and ceil values
List<Integer> result = sol.floorCeilOfBST(root, key);
System.out.println("Floor: " + result.get(0) + ", Ceil: " + result.get(1));
}
}
# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, val=0, left=None, right=None):
self.data = val
self.left = left
self.right = right
class Solution:
def floorCeilOfBST(self, root, key):
# Initialize floor and ceil values to -1, indicating not found
floor = -1
ceil = -1
# Find the floor value
# Start from the root of the BST
current = root
while current:
# If the key matches the current node's value
if current.data == key:
# Set floor to this value
floor = current.data
break
# If the key is greater than the current node's value
# Update floor to the current node's value
# If the key is smaller than the current node's value
# Move to the left subtree to find a smaller value
elif current.data < key:
floor = current.data
current = current.right
else:
current = current.left
# Find the ceil value
# Reset current to start from the root again
current = root
while current:
# If the key matches the current node's value
if current.data == key:
# Set ceil to this value
ceil = current.data
break
# If the key is smaller than the current node's value
# Update ceil to the current node's value
# If the key is greater than the current node's value
# Move to the right subtree to find a larger value
elif current.data > key:
ceil = current.data
current = current.left
else:
current = current.right
# Return floor and ceil values as a list
return [floor, ceil]
if __name__ == "__main__":
# Creating a sample BST
root = TreeNode(8)
root.left = TreeNode(4)
root.right = TreeNode(12)
root.left.left = TreeNode(2)
root.left.right = TreeNode(6)
root.right.left = TreeNode(10)
root.right.right = TreeNode(14)
sol = Solution()
key = 11 # Key to find floor and ceil for
# Find and print floor and ceil values
result = sol.floorCeilOfBST(root, key)
print(f"Floor: {result[0]}, Ceil: {result[1]}")
// Definition for a binary tree node.
class TreeNode {
constructor(val = 0, left = null, right = null){
this.data = val;
this.left = null;
this.right = null;
}
}
class Solution {
floorCeilOfBST(root, key) {
// Initialize floor and ceil values to -1, indicating not found
let floor = -1;
let ceil = -1;
// Find the floor value
// Start from the root of the BST
let current = root;
while (current !== null) {
// If the key matches the current node's value
if (current.data === key) {
// Set floor to this value
floor = current.data;
break;
/* If the key is greater than the current node's value
Update floor to the current node's value
If the key is smaller than the current node's value
Move to the left subtree to find a smaller value */
} else if (current.data < key) {
floor = current.data;
current = current.right;
} else {
current = current.left;
}
}
// Find the ceil value
// Reset current to start from the root again
current = root;
while (current !== null) {
// If the key matches the current node's value
if (current.data === key) {
// Set ceil to this value
ceil = current.data;
break;
/* If the key is smaller than the current node's value
Update ceil to the current node's value
If the key is greater than the current node's value
Move to the right subtree to find a larger value */
} else if (current.data > key) {
ceil = current.data;
current = current.left;
} else {
current = current.right;
}
}
// Return floor and ceil values as an array
return [floor, ceil];
}
}
// Helper function to create a sample BST and find floor and ceil values
function main() {
// Creating a sample BST
let root = new TreeNode(8);
root.left = new TreeNode(4);
root.right = new TreeNode(12);
root.left.left = new TreeNode(2);
root.left.right = new TreeNode(6);
root.right.left = new TreeNode(10);
root.right.right = new TreeNode(14);
let sol = new Solution();
let key = 11; // Key to find floor and ceil for
// Find and print floor and ceil values
let result = sol.floorCeilOfBST(root, key);
console.log("Floor: " + result[0] + ", Ceil: " + result[1]);
}
// Execute the main function
main();
Time Complexity : O(H) where h is the height of the BST, since we traverse down the tree once for each of the floor and ceil searches
Space Complexity : O(1) as we only use a constant amount of extra space for storing the floor and ceil values.
The goal of finding the ceil value in a Binary Search Tree (BST) is to keep track of the smallest node value that is greater than or equal to the given key. The thought process involves traversing the tree, continuing until either the tree is fully explored or the key is found. During traversal, if the key matches the node’s value, this value is directly assigned as the ceiling and the search ends. If the key is greater than the current node’s value, the algorithm moves to the right subtree to find a larger value. If the key is smaller, the algorithm updates the ceil value with the current node’s value and explores the left subtree for potentially smaller values.
ceil
to -1 to store the ceiling value initially.ceil
with the current node’s value and move to the left subtree.ceil
value if the key is not found in the tree. This ceil
value represents the smallest node value greater than the key, or -1 if no such value exists in the BST.#include <bits/stdc++.h>
using namespace std;
// Definition for a binary tree node.
class TreeNode {
public:
int data;
TreeNode *left;
TreeNode *right;
TreeNode(int val) : data(val), left(nullptr), right(nullptr) {}
};
class Solution {
public:
vector<int> floorCeilOfBST(TreeNode* root, int key) {
// Initialize the floor and ceil values
int floor = -1;
int ceil = -1;
// Find the floor value
// Start from the root of the BST
TreeNode* current = root;
while (current) {
// If the key matches the current node's value
if (current->data == key) {
// Set floor to this value
floor = current->data;
break;
/* If the key is greater than the current node's value
Update floor to the current node's value
If the key is smaller than the current node's value
Move to the left subtree to find a smaller value */
} else if (current->data < key) {
floor = current->data;
current = current->right;
} else {
current = current->left;
}
}
// Find the ceil value
// Reset current to start from the root again
current = root;
while (current) {
// If the key matches the current node's value
if (current->data == key) {
// Set ceil to this value
ceil = current->data;
break;
/* If the key is smaller than the current node's value
Update ceil to the current node's value
If the key is greater than the current node's value
Move to the right subtree to find a larger value */
} else if (current->data > key) {
ceil = current->data;
current = current->left;
} else {
current = current->right;
}
}
// Return the floor and ceil values as a vector
return {floor, ceil};
}
};
// Utility function to insert a new node with given key in BST
TreeNode* insert(TreeNode* node, int key) {
if (node == nullptr) return new TreeNode(key);
if (key < node->data)
node->left = insert(node->left, key);
else if (key > node->data)
node->right = insert(node->right, key);
return node;
}
int main() {
// Create the BST
TreeNode* root = nullptr;
root = insert(root, 8);
insert(root, 4);
insert(root, 12);
insert(root, 2);
insert(root, 6);
insert(root, 10);
insert(root, 14);
// Key value to find floor and ceil for
int key = 11;
// Solution instance
Solution sol;
vector<int> result = sol.floorCeilOfBST(root, key);
// Output the floor and ceil values
cout << "Floor: " << result[0] << ", Ceil: " << result[1] << endl;
return 0;
}
import java.util.*;
class TreeNode {
int data;
TreeNode left, right;
TreeNode(int val) {
data = val;
left = right = null;
}
}
class Solution {
public List<Integer> floorCeilOfBST(TreeNode root, int key) {
// Initialize floor and ceil values to -1, indicating not found
int floor = -1;
int ceil = -1;
// Find the floor value
// Start from the root of the BST
TreeNode current = root;
while (current != null) {
// If the key matches the current node's value
if (current.data == key) {
// Set floor to this value
floor = current.data;
break;
/* If the key is greater than the current node's value
Update floor to the current node's value
If the key is smaller than the current node's value
Move to the left subtree to find a smaller value */
} else if (current.data < key) {
floor = current.data;
current = current.right;
} else {
current = current.left;
}
}
// Find the ceil value
// Reset current to start from the root again
current = root;
while (current != null) {
// If the key matches the current node's value
if (current.data == key) {
// Set ceil to this value
ceil = current.data;
break;
/* If the key is smaller than the current node's value
Update ceil to the current node's value
If the key is greater than the current node's value
Move to the right subtree to find a larger value */
} else if (current.data > key) {
ceil = current.data;
current = current.left;
} else {
current = current.right;
}
}
// Return floor and ceil values as a list
return Arrays.asList(floor, ceil);
}
public static void main(String[] args) {
// Creating a sample BST
TreeNode root = new TreeNode(8);
root.left = new TreeNode(4);
root.right = new TreeNode(12);
root.left.left = new TreeNode(2);
root.left.right = new TreeNode(6);
root.right.left = new TreeNode(10);
root.right.right = new TreeNode(14);
Solution sol = new Solution();
int key = 11; // Key to find floor and ceil for
// Find and print floor and ceil values
List<Integer> result = sol.floorCeilOfBST(root, key);
System.out.println("Floor: " + result.get(0) + ", Ceil: " + result.get(1));
}
}
# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, val=0, left=None, right=None):
self.data = val
self.left = left
self.right = right
class Solution:
def floorCeilOfBST(self, root, key):
# Initialize floor and ceil values to -1, indicating not found
floor = -1
ceil = -1
# Find the floor value
# Start from the root of the BST
current = root
while current:
# If the key matches the current node's value
if current.data == key:
# Set floor to this value
floor = current.data
break
# If the key is greater than the current node's value
# Update floor to the current node's value
# If the key is smaller than the current node's value
# Move to the left subtree to find a smaller value
elif current.data < key:
floor = current.data
current = current.right
else:
current = current.left
# Find the ceil value
# Reset current to start from the root again
current = root
while current:
# If the key matches the current node's value
if current.data == key:
# Set ceil to this value
ceil = current.data
break
# If the key is smaller than the current node's value
# Update ceil to the current node's value
# If the key is greater than the current node's value
# Move to the right subtree to find a larger value
elif current.data > key:
ceil = current.data
current = current.left
else:
current = current.right
# Return floor and ceil values as a list
return [floor, ceil]
if __name__ == "__main__":
# Creating a sample BST
root = TreeNode(8)
root.left = TreeNode(4)
root.right = TreeNode(12)
root.left.left = TreeNode(2)
root.left.right = TreeNode(6)
root.right.left = TreeNode(10)
root.right.right = TreeNode(14)
sol = Solution()
key = 11 # Key to find floor and ceil for
# Find and print floor and ceil values
result = sol.floorCeilOfBST(root, key)
print(f"Floor: {result[0]}, Ceil: {result[1]}")
// Definition for a binary tree node.
class TreeNode {
constructor(val = 0, left = null, right = null){
this.data = val;
this.left = null;
this.right = null;
}
}
class Solution {
floorCeilOfBST(root, key) {
// Initialize floor and ceil values to -1, indicating not found
let floor = -1;
let ceil = -1;
// Find the floor value
// Start from the root of the BST
let current = root;
while (current !== null) {
// If the key matches the current node's value
if (current.data === key) {
// Set floor to this value
floor = current.data;
break;
/* If the key is greater than the current node's value
Update floor to the current node's value
If the key is smaller than the current node's value
Move to the left subtree to find a smaller value */
} else if (current.data < key) {
floor = current.data;
current = current.right;
} else {
current = current.left;
}
}
// Find the ceil value
// Reset current to start from the root again
current = root;
while (current !== null) {
// If the key matches the current node's value
if (current.data === key) {
// Set ceil to this value
ceil = current.data;
break;
/* If the key is smaller than the current node's value
Update ceil to the current node's value
If the key is greater than the current node's value
Move to the right subtree to find a larger value */
} else if (current.data > key) {
ceil = current.data;
current = current.left;
} else {
current = current.right;
}
}
// Return floor and ceil values as an array
return [floor, ceil];
}
}
// Helper function to create a sample BST and find floor and ceil values
function main() {
// Creating a sample BST
let root = new TreeNode(8);
root.left = new TreeNode(4);
root.right = new TreeNode(12);
root.left.left = new TreeNode(2);
root.left.right = new TreeNode(6);
root.right.left = new TreeNode(10);
root.right.right = new TreeNode(14);
let sol = new Solution();
let key = 11; // Key to find floor and ceil for
// Find and print floor and ceil values
let result = sol.floorCeilOfBST(root, key);
console.log("Floor: " + result[0] + ", Ceil: " + result[1]);
}
// Execute the main function
main();
Time Complexity : O(H) where h is the height of the BST, since we traverse down the tree once for each of the floor and ceil searches
Space Complexity : O(1) as we only use a constant amount of extra space for storing the floor and ceil values.
Q: What happens if all values in the BST are greater than key?
A: If every node in the BST is greater than key, no floor exists (floor = -1), and the smallest node becomes the ceil.
Q: Why can’t we search for both floor and ceil in one pass?
A: We can search for both in a single traversal using the BST property. Instead of performing separate searches, we update floor and ceil dynamically during one DFS/BFS traversal.
Q: Can this be optimized further for very large trees?
A: For large-scale BSTs (like B-Trees used in databases), balanced partitioning and cached floor/ceil lookups speed up queries significantly.
Q: How would this be implemented in an AVL tree?
A: Since AVL trees are self-balancing, search operations remain O(log n), preventing the worst-case O(n) scenario seen in skewed BSTs. The algorithm remains the same but benefits from faster lookups.