Bird
Raised Fist0
DSA Goprogramming

Floor and Ceil in BST in DSA Go

Choose your learning style10 modes available
Mental Model
Floor is the biggest value smaller or equal to target; Ceil is the smallest value bigger or equal to target in the BST.
Analogy: Imagine a bookshelf sorted by book height. Floor is the tallest book not taller than your target height, and Ceil is the shortest book not shorter than your target height.
       8
      / \
     4   12
    / \   / \
   2   6 10  14
Dry Run Walkthrough
Input: BST: 8->4->12->2->6->10->14, find floor and ceil of 5
Goal: Find the floor and ceil values for 5 in the BST
Step 1: Start at root node 8, compare 5 with 8
8[compare with 5] -> 4 -> 12 -> 2 -> 6 -> 10 -> 14
Why: We start at root to decide which subtree to explore
Step 2: Since 5 < 8, move to left child 4
8 -> 4[compare with 5] -> 12 -> 2 -> 6 -> 10 -> 14
Why: Values smaller than 8 are in left subtree
Step 3: Since 5 > 4, floor candidate updated to 4, move to right child 6
8 -> 4[floor=4] -> 12 -> 2 -> 6[compare with 5] -> 10 -> 14
Why: 4 is less than 5, so it could be floor; check right subtree for closer value
Step 4: Since 5 < 6, ceil candidate updated to 6, move to left child which is null
8 -> 4[floor=4] -> 12 -> 2 -> 6[ceil=6] -> 10 -> 14
Why: 6 is greater than 5, so it could be ceil; no left child to explore
Step 5: No more nodes to explore, return floor=4 and ceil=6
Final floor=4, ceil=6
Why: We found closest smaller and bigger values around 5
Result:
4 -> 6
Annotated Code
DSA Go
package main

import "fmt"

type Node struct {
	val   int
	left  *Node
	right *Node
}

func insert(root *Node, val int) *Node {
	if root == nil {
		return &Node{val: val}
	}
	if val < root.val {
		root.left = insert(root.left, val)
	} else {
		root.right = insert(root.right, val)
	}
	return root
}

func floorCeil(root *Node, target int) (floor *int, ceil *int) {
	var f, c *int
	curr := root
	for curr != nil {
		if curr.val == target {
			f = &curr.val
			c = &curr.val
			break
		} else if curr.val > target {
			c = &curr.val // update ceil candidate
			curr = curr.left // go left to find smaller or equal
		} else {
			f = &curr.val // update floor candidate
			curr = curr.right // go right to find bigger or equal
		}
	}
	return f, c
}

func main() {
	var root *Node
	values := []int{8, 4, 12, 2, 6, 10, 14}
	for _, v := range values {
		root = insert(root, v)
	}
	floor, ceil := floorCeil(root, 5)
	if floor != nil {
		fmt.Printf("Floor: %d\n", *floor)
	} else {
		fmt.Println("Floor: nil")
	}
	if ceil != nil {
		fmt.Printf("Ceil: %d\n", *ceil)
	} else {
		fmt.Println("Ceil: nil")
	}
}
for curr != nil {
loop through nodes to find floor and ceil candidates
if curr.val == target {
exact match found, floor and ceil are the same
else if curr.val > target {
current node value is bigger, update ceil and go left
else {
current node value is smaller, update floor and go right
OutputSuccess
Floor: 4 Ceil: 6
Complexity Analysis
Time: O(h) where h is the height of the BST because we traverse from root down to a leaf at most once
Space: O(1) because we use only a few pointers and no extra data structures
vs Alternative: Compared to scanning all nodes (O(n)), this approach uses BST properties to find floor and ceil efficiently in O(h)
Edge Cases
target smaller than all nodes
floor is nil, ceil is smallest node
DSA Go
c = &curr.val // update ceil candidate
target larger than all nodes
ceil is nil, floor is largest node
DSA Go
f = &curr.val // update floor candidate
target equals a node value
floor and ceil both equal target
DSA Go
if curr.val == target { f = &curr.val; c = &curr.val; break }
When to Use This Pattern
When asked to find closest smaller or bigger values in a BST, use floor and ceil search by moving left or right based on comparisons.
Common Mistakes
Mistake: Not updating floor or ceil candidates correctly when moving left or right
Fix: Update floor when moving right (smaller values), update ceil when moving left (bigger values)
Summary
Find the closest smaller or equal (floor) and closest bigger or equal (ceil) values to a target in a BST.
Use when you need nearest bounds of a value in a sorted tree structure.
The key is to move left or right while updating floor or ceil candidates based on comparisons.

Practice

(1/5)
1. What does the floor of a value in a Binary Search Tree (BST) represent?
easy
A. The smallest value in the BST less than the given value
B. The smallest value in the BST greater than or equal to the given value
C. The root value of the BST
D. The greatest value in the BST less than or equal to the given value

Solution

  1. Step 1: Understand the floor concept in BST

    The floor of a value is the largest value in the BST that is less than or equal to the given value.
  2. Step 2: Compare with options

    The greatest value in the BST less than or equal to the given value matches this definition exactly, while others describe different concepts.
  3. Final Answer:

    The greatest value in the BST less than or equal to the given value -> Option D
  4. Quick Check:

    Floor = greatest ≤ value [OK]
Hint: Floor is largest ≤ value in BST [OK]
Common Mistakes:
  • Confusing floor with ceil
  • Thinking floor is smallest value
  • Assuming floor is always root
2. Which of the following Go function signatures correctly represents a function to find the ceil in a BST for an integer key?
easy
A. func ceil(root *Node, key int) int
B. func ceil(key int, root *Node) int
C. func ceil(root Node, key int) int
D. func ceil(root *Node, key string) int

Solution

  1. Step 1: Check parameter order and types

    The function should take a pointer to the root node and an integer key to search for ceil.
  2. Step 2: Validate options

    func ceil(root *Node, key int) int uses pointer to Node and int key in correct order. Swapping parameters to key first is wrong, using value Node instead of pointer is wrong, using string for key is wrong.
  3. Final Answer:

    func ceil(root *Node, key int) int -> Option A
  4. Quick Check:

    Pointer root and int key correct [OK]
Hint: Pointer root first, key int second [OK]
Common Mistakes:
  • Swapping parameter order
  • Using value instead of pointer for root
  • Wrong key data type
3. Given the BST below and key = 14, what is the ceil value returned by the following Go code?
type Node struct {
  val int
  left, right *Node
}

func ceil(root *Node, key int) int {
  if root == nil {
    return -1
  }
  if root.val == key {
    return root.val
  }
  if root.val < key {
    return ceil(root.right, key)
  }
  ceilVal := ceil(root.left, key)
  if ceilVal >= key && ceilVal != -1 {
    return ceilVal
  }
  return root.val
}

// BST structure:
//       10
//      /  \
//     5    15
//         /  \
//        12   20

// Call: ceil(root, 14)
medium
A. 15
B. 12
C. 20
D. -1

Solution

  1. Step 1: Trace ceil function with key=14

    Start at root 10: 10 < 14, go right to 15. 15 > 14, check left subtree of 15 (12). 12 < 14, so ceil(12) returns -1, so return 15.
  2. Step 2: Confirm returned ceil value

    Ceil is 15, the smallest value ≥ 14 in BST.
  3. Final Answer:

    15 -> Option A
  4. Quick Check:

    Ceil(14) = 15 [OK]
Hint: Ceil is smallest ≥ key, check right if less [OK]
Common Mistakes:
  • Returning 12 instead of 15
  • Returning -1 when ceil exists
  • Confusing floor and ceil logic
4. The following Go code attempts to find the floor in a BST but returns incorrect results. What is the bug?
func floor(root *Node, key int) int {
  if root == nil {
    return -1
  }
  if root.val == key {
    return root.val
  }
  if root.val > key {
    return floor(root.left, key)
  }
  floorVal := floor(root.right, key)
  if floorVal <= key {
    return floorVal
  }
  return root.val
}
medium
A. The function should check 'floorVal >= key' instead
B. The condition 'floorVal <= key' should be 'floorVal != -1'
C. The base case should return 0 instead of -1
D. The recursive call on left subtree is incorrect

Solution

  1. Step 1: Analyze floorVal condition

    The code checks if floorVal <= key, but floorVal can be -1 (no floor found). This causes wrong returns.
  2. Step 2: Correct condition for valid floorVal

    It should check if floorVal != -1 to confirm a valid floor before returning it; otherwise return root.val.
  3. Final Answer:

    The condition 'floorVal <= key' should be 'floorVal != -1' -> Option B
  4. Quick Check:

    Check floorVal != -1 before return [OK]
Hint: Check for -1 (no floor) before returning floorVal [OK]
Common Mistakes:
  • Ignoring -1 as invalid floor
  • Wrong comparison operators
  • Changing base case return value
5. You have a BST with nodes: 8, 4, 12, 2, 6, 10, 14. You want to find both floor and ceil for key = 5 using a single traversal function. Which approach is best to implement this efficiently?
hard
A. Use inorder traversal and store all nodes in array, then binary search
B. Traverse left subtree for floor, right subtree for ceil separately
C. Traverse once, update floor when node.val ≤ key, update ceil when node.val ≥ key
D. Find floor first, then restart traversal to find ceil

Solution

  1. Step 1: Understand single traversal for floor and ceil

    During one traversal, compare node values with key. Update floor if node.val ≤ key and is greater than current floor. Update ceil if node.val ≥ key and is less than current ceil.
  2. Step 2: Compare approaches

    Traverse once, update floor when node.val ≤ key, update ceil when node.val ≥ key efficiently finds both in one pass. Options B and C require multiple traversals. Use inorder traversal and store all nodes in array, then binary search uses extra space and is less efficient.
  3. Final Answer:

    Traverse once, update floor when node.val ≤ key, update ceil when node.val ≥ key -> Option C
  4. Quick Check:

    Single pass update floor & ceil [OK]
Hint: Update floor and ceil in one BST traversal [OK]
Common Mistakes:
  • Doing separate traversals for floor and ceil
  • Using extra space unnecessarily
  • Restarting traversal multiple times
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard