Bird
Raised Fist0
Interview Prepbinary-search-treesmediumAmazonGoogle

Balance a BST

Choose your preparation mode4 modes available
▶
Steps
setup

Initialize nodes list and start inorder traversal

Create an empty list 'nodes' to store nodes in sorted order. Begin inorder traversal from the root node (value 1).

💡 This step sets up the data structure to collect nodes in ascending order, which is key to balancing.
Line:nodes = [] def inorder(node: Optional[TreeNode]): if not node: return
💡 The inorder traversal will visit nodes in ascending order, which is essential for balanced BST construction.
📊
Balance a BST - Watch the Algorithm Execute, Step by Step
Watching the algorithm step-by-step reveals how the skewed BST is transformed into a balanced one by reorganizing nodes based on inorder traversal.
Step 1/20
·Active fill★Answer cell
Current node: 1
1234
DFS Stack
1 (entered)
1234
DFS Stack
1 (left_done)
Current node: 1
1234
DFS Stack
1 (node_added)
Result: [1]
Current node: 2
1234
DFS Stack
2 (entered)
Result: [1]
1234
DFS Stack
2 (left_done)
Result: [1]
Current node: 2
1234
DFS Stack
2 (node_added)
Result: [1, 2]
Current node: 3
1234
DFS Stack
3 (entered)
Result: [1, 2]
1234
DFS Stack
3 (left_done)
Result: [1, 2]
Current node: 3
1234
DFS Stack
3 (node_added)
Result: [1, 2, 3]
Current node: 4
1234
DFS Stack
4 (entered)
Result: [1, 2, 3]
1234
DFS Stack
4 (left_done)
Result: [1, 2, 3]
Current node: 4
1234
Result: [1, 2, 3, 4]
1234
Result: [1, 2, 3, 4]
Current node: 2
1234
Result: [1, 2, 3, 4]
Current node: 2
1234
Result: [1, 2, 3, 4]
Current node: 3
1234
Result: [1, 2, 3, 4]
Current node: 3
1234
Result: [1, 2, 3, 4]
Current node: 4
1234
Result: [1, 2, 3, 4]
1234
Result: [1, 2, 3, 4]
Current node: 2
1234
Result: [1, 2, 3, 4]
Return: 2

Key Takeaways

✓ Inorder traversal collects nodes in sorted order, which is the foundation for balancing the BST.

This insight is hard to see from code alone because the traversal and balancing are separate phases.

✓ Choosing the middle node of the sorted nodes array as root at each step ensures the tree is balanced.

Visualizing the middle selection clarifies how the tree height is minimized.

✓ Using a stack to iteratively build the balanced BST replaces recursion and manages subtree construction explicitly.

Seeing the stack operations helps understand how the algorithm controls subtree boundaries.

Practice

(1/5)
1. Given the following code snippet for converting a sorted array to a height-balanced BST, what is the value of the root node's value after the first call to helper with input nums = [1, 3, 5]?
easy
A. 3
B. 1
C. 5
D. None

Solution

  1. Step 1: Calculate mid index for initial call

    For nums=[1,3,5], left=0, right=2, mid=(0+2)//2=1.
  2. Step 2: Identify root value

    nums[mid] = nums[1] = 3, so root node value is 3.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Mid index calculation picks 3 as root [OK]
Hint: Mid index picks middle element as root [OK]
Common Mistakes:
  • Choosing first or last element as root
  • Off-by-one mid calculation
2. Given the following code for inserting a value into a BST, what will be the value of the variable parent.val when inserting 5 into the BST rooted at 4 with left child 2 and right child 7?
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def insertIntoBST(root, val):
    if root is None:
        return TreeNode(val)
    curr = root
    parent = None
    while curr:
        parent = curr
        if val < curr.val:
            if curr.left is None:
                curr.left = TreeNode(val)
                return root
            curr = curr.left
        else:
            if curr.right is None:
                curr.right = TreeNode(val)
                return root
            curr = curr.right
    return root

root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(7)
val = 5
insertIntoBST(root, val)
easy
A. 4
B. 7
C. 2
D. 5

Solution

  1. Step 1: Trace insertion path

    Start at root (4). Since 5 > 4, move right to node 7. Update parent to 4.
  2. Step 2: Check right child of 7

    5 < 7, so move left. Left child of 7 is None, so insert here. Parent is now 7, but last parent before insertion was 4.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Parent is last non-null node before insertion -> 4 [OK]
Hint: Parent tracks last node before insertion point [OK]
Common Mistakes:
  • Confusing parent with current node
  • Off-by-one in loop iteration
  • Mistaking inserted value as parent
3. Consider the following buggy code for deleting a node in a BST. Which line contains the subtle bug that can cause the BST property to break when deleting a node with two children?
def deleteNode(root, key):
    if not root:
        return null
    if key < root.val:
        root.left = deleteNode(root.left, key)
    elif key > root.val:
        root.right = deleteNode(root.right, key)
    else:
        if not root.left:
            return root.right
        elif not root.right:
            return root.left
        else:
            successor = findSuccessor(root)
            root.val = successor.val
            root.left = deleteNode(root.right, successor.val)  # Bug here
    return root
medium
A. Line where root.left is assigned deleteNode(root.right, successor.val)
B. Line where root.left is assigned deleteNode(root.left, key)
C. Line where root.val is set to successor.val
D. Line where root.right is assigned deleteNode(root.right, key)

Solution

  1. Step 1: Identify two-children deletion logic

    When deleting a node with two children, we replace its value with the successor's value and then delete the successor from the right subtree.
  2. Step 2: Spot incorrect subtree assignment

    The line assigns root.left = deleteNode(root.right, successor.val), which incorrectly deletes from the right subtree but assigns result to left child, breaking BST structure.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Correct line should assign root.right = deleteNode(root.right, successor.val) [OK]
Hint: Deleting successor must update right subtree, not left [OK]
Common Mistakes:
  • Mixing left and right subtree assignments
  • Forgetting to update parent's child pointer
  • Replacing value but not deleting successor
4. The following code attempts to validate a BST using inorder traversal. Which line contains a subtle bug that can cause incorrect results on some inputs?
medium
A. Line checking if node is null (if not node: return true)
B. Line updating prev[0] = node.val
C. Line comparing node.val < prev[0] instead of node.val <= prev[0]
D. Line calling inorder(node.left)

Solution

  1. Step 1: Identify BST strict inequality

    BST requires node.val to be strictly greater than previous inorder value; using < instead of <= allows duplicates.
  2. Step 2: Understand impact of bug

    Using node.val < prev[0] misses the case when node.val == prev[0], incorrectly allowing duplicates and invalid BSTs.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Strict inequality check is essential to reject duplicates [OK]
Hint: BST nodes must be strictly increasing in inorder traversal [OK]
Common Mistakes:
  • Allowing duplicates by using < instead of <=
  • Not resetting prev between calls
  • Only comparing immediate children
5. Suppose the BST can contain duplicate values, and you want to find the lowest common ancestor of two nodes p and q that may have the same value. Which modification to the optimal iterative algorithm correctly handles duplicates while maintaining efficiency?
hard
A. Define a consistent rule that duplicates go to the right subtree and use original algorithm without changes.
B. Modify comparisons to use '<=' and '>=' to ensure traversal includes duplicates on both sides.
C. Augment each node with a count of duplicates and traverse left or right based on counts to find LCA.
D. Store paths from root to p and q and compare them to find LCA, since BST property is ambiguous with duplicates.

Solution

  1. Step 1: Understand duplicate handling in BST

    BSTs with duplicates require a consistent insertion rule, commonly duplicates go to right subtree.
  2. Step 2: Modify comparisons to include duplicates

    Using '<=' and '>=' in comparisons ensures traversal includes duplicates correctly on both sides.
  3. Step 3: Avoid ambiguous or inefficient methods

    Path comparison or augmenting nodes adds overhead and complexity.
  4. Final Answer:

    Option B -> Option B
  5. Quick Check:

    Inclusive comparisons handle duplicates while preserving efficiency [OK]
Hint: Modify comparison operators to handle duplicates correctly [OK]
Common Mistakes:
  • Using strict comparisons that miss duplicates
  • Reverting to path comparison losing efficiency
  • Adding unnecessary data structures
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