class Node { val: number; left: Node | null; right: Node | null; constructor(val: number) { this.val = val; this.left = null; this.right = null; } } function insert(root: Node | null, val: number): Node { if (!root) return new Node(val); if (val < root.val) root.left = insert(root.left, val); else root.right = insert(root.right, val); return root; } function floor(root: Node | null, key: number): number | null { let res: number | null = null; while (root) { if (root.val === key) return root.val; if (root.val > key) root = root.left; else { res = root.val; root = root.right; } } return res; } function ceil(root: Node | null, key: number): number | null { let res: number | null = null; while (root) { if (root.val === key) return root.val; if (root.val < key) root = root.right; else { res = root.val; root = root.left; } } return res; } const values = [10, 5, 18, 3, 7, 12, 20]; let root: Node | null = null; for (const v of values) { root = insert(root, v); } const key = 15; const floorVal = floor(root, key); const ceilVal = ceil(root, key); console.log(`Floor: ${floorVal}, Ceil: ${ceilVal}`);
The floor is the greatest value less than or equal to the key. For 15, the floor is 12.
The ceil is the smallest value greater than or equal to the key. For 15, the ceil is 18.
In the worst case, the BST is skewed, so floor function visits all nodes along the path, which can be O(n).
function ceil(root: Node | null, key: number): number {
let res: number | null = null;
while (root) {
if (root.val === key) return root.val;
if (root.val < key) root = root.right;
else {
res = root.val;
root = root.left;
}
}
return res!;
}If the key is larger than all nodes, res stays null. Using res! forces a non-null return, causing a runtime error.
class Node { val: number; left: Node | null; right: Node | null; constructor(val: number) { this.val = val; this.left = null; this.right = null; } } function insert(root: Node | null, val: number): Node { if (!root) return new Node(val); if (val < root.val) root.left = insert(root.left, val); else root.right = insert(root.right, val); return root; } function floor(root: Node | null, key: number): number | null { let res: number | null = null; while (root) { if (root.val === key) return root.val; if (root.val > key) root = root.left; else { res = root.val; root = root.right; } } return res; } function ceil(root: Node | null, key: number): number | null { let res: number | null = null; while (root) { if (root.val === key) return root.val; if (root.val < key) root = root.right; else { res = root.val; root = root.left; } } return res; } const values = [8, 4, 12, 2, 6, 10, 14]; let root: Node | null = null; for (const v of values) { root = insert(root, v); } const key = 5; const floorVal = floor(root, key); const ceilVal = ceil(root, key); console.log(`Floor: ${floorVal}, Ceil: ${ceilVal}`);
Floor is the greatest value less than or equal to 5, which is 4.
Ceil is the smallest value greater than or equal to 5, which is 6.
Balanced BST has height about log n, so floor and ceil run in O(log n).
Skewed BST is like a linked list, so operations degrade to O(n).
