Bird
Raised Fist0
Interview Prepbinary-search-treeshardAmazonGoogleMicrosoft

Recover Binary Search Tree (Two Nodes Swapped)

Choose your preparation mode4 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Steps
setup

Initialize pointers and start at root

Initialize first, second, and prev pointers to None. Set current pointer to root node (value 1).

💡 Setting up pointers is essential to track nodes during traversal and detect violations.
Line:first = second = prev = None current = root
💡 We start traversal at the root with no nodes visited yet.
📊
Recover Binary Search Tree (Two Nodes Swapped) - Watch the Algorithm Execute, Step by Step
Watching the algorithm step-by-step reveals how the Morris traversal avoids extra space and how the swapped nodes are identified by violations in inorder sequence.
Step 1/10
·Active fillAnswer cell
Current node: 1
132
132
Current node: 2
132
Current node: 2
132
Current node: 3
132
Current node: 3
132
132
312
312
312
Return: "[3,1,null,null,2]"

Key Takeaways

Morris inorder traversal allows O(1) space traversal by temporarily modifying tree links.

This is hard to see from code alone because the threaded links are subtle and invisible without visualization.

Violations in inorder sequence (prev.val > current.val) identify the two swapped nodes.

Visualizing the comparisons clarifies how the algorithm detects exactly which nodes to swap.

Swapping values of the two identified nodes restores the BST without changing tree structure.

Seeing the final swap in the tree confirms the correctness of the approach beyond just code logic.

Practice

(1/5)
1. 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
2. Consider the following code for finding the lowest common ancestor in a BST. Given the BST below and nodes p=2 and q=8, what value does the function return? BST structure: 6 / \ 2 8 / \ \ 0 4 9 / \ 3 5
easy
A. 2
B. 8
C. 4
D. 6

Solution

  1. Step 1: Trace first iteration with current=6

    p=2 and q=8; 2 < 6 and 8 > 6, so current is split point; return 6.
  2. Step 2: Confirm no further traversal

    Since p and q lie on different sides of 6, 6 is the LCA.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Split point found at root 6 immediately [OK]
Hint: LCA is where paths to p and q diverge [OK]
Common Mistakes:
  • Returning smaller node instead of split point
  • Confusing left/right subtree traversal
  • Off-by-one error in loop conditions
3. What is the time complexity of the optimal iterative approach that converts a BST to a Greater Tree using reverse inorder traversal with an explicit stack?
medium
A. O(n) where n is the number of nodes in the BST
B. O(n · h) where n is number of nodes and h is tree height
C. O(n · log n) due to stack operations on balanced BST
D. O(h) where h is the height of the BST because each node is visited once

Solution

  1. Step 1: Identify number of nodes visited

    Each node is visited exactly once during traversal.
  2. Step 2: Analyze stack operations and overall traversal

    While each node is visited once, the explicit stack can hold up to h nodes, and each push/pop operation can be considered O(1). However, in the worst case (unbalanced tree), the height h can be up to n, making the complexity O(n * h).
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Worst-case complexity depends on tree height [OK]
Hint: Worst-case complexity depends on tree height [OK]
Common Mistakes:
  • Assuming stack operations multiply complexity by height unnecessarily
  • Confusing recursion stack space with time complexity
  • Thinking balanced BST implies O(n log n) time
4. Consider the following buggy code snippet for converting a sorted array to a height-balanced BST. Which line contains the subtle bug that can cause infinite recursion or stack overflow?
medium
A. Line 5: left_child = self.helper(nums, left, mid - 1)
B. Line 3: mid = (left + right) // 2
C. Line 7: root.right = self.helper(nums, mid + 1, right)
D. Line 2: if left >= right: return None

Solution

  1. Step 1: Understand base case condition

    The base case should be when left > right, not left >= right, to allow single-element subarrays.
  2. Step 2: Consequence of incorrect base case

    Using left >= right causes the recursion to skip processing subarrays of size 1, leading to infinite recursion or missing nodes.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Base case must allow left == right to process single elements [OK]
Hint: Base case must be left > right, not left >= right [OK]
Common Mistakes:
  • Incorrect base case causing infinite recursion
  • Misplaced mid calculation
5. 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