BST In order Predecessor - codepath/compsci_guides GitHub Wiki

Unit 8 Session 2 (Click for link to problem statements)

Problem Highlights

  • 💡 Difficulty: Medium
  • Time to complete: 20 mins
  • 🛠️ Topics: Trees, Binary Search Trees, In-Order Predecessor

1: U-nderstand

Understand what the interviewer is asking for by using test cases and questions about the problem.

  • Established a set (2-3) of test cases to verify their own solution later.
  • Established a set (1-2) of edge cases to verify their solution handles complexities.
  • Have fully understood the problem and have no clarifying questions.
  • Have you verified any Time/Space Constraints for this problem?
  • Question: What should be done if there is no in-order predecessor available?
    • Answer: Return None if there is no in-order predecessor, such as when the node is the leftmost node.
HAPPY CASE
Input: BST with nodes [20, 10, 30, 5, 15], search in-order predecessor of 10
Output: 5
Explanation: 5 is the in-order predecessor of 10 as it is the largest value less than 10.

EDGE CASE
Input: BST with nodes [20, 10, 30, 5, 15], search in-order predecessor of 5
Output: None
Explanation: 5 is the leftmost node, so it has no predecessor.

2: M-atch

Match what this problem looks like to known categories of problems, e.g., Linked List or Dynamic Programming, and strategies or patterns in those categories.

This problem involves navigating through a binary search tree (BST) to find the in-order predecessor, utilizing the properties of BSTs to efficiently find the required node.

3: P-lan

Plan the solution with appropriate visualizations and pseudocode.

General Idea: Utilize the properties of BSTs to find the in-order predecessor of a node.

1) If the node has a left subtree, the in-order predecessor is the rightmost node of this subtree.
2) If the node has no left subtree, the predecessor is one of its ancestors; specifically, the nearest ancestor for which this node is in the right subtree.
3) Traverse the tree from the root to find the node and keep track of the potential predecessor.

⚠️ Common Mistakes

  • Incorrectly identifying the in-order predecessor or failing to handle the absence of a left subtree.

4: I-mplement

Implement the code to solve the algorithm.

def inorder_predecessor(root, current):
    "
    Find the in-order predecessor of a given node in a BST.
    "
    predecessor = None
    while root:
        if current.val > root.val:
            predecessor = root
            root = root.right
        elif current.val < root.val:
            root = root.left
        else:
            if root.left:
                predecessor = find_rightmost(root.left)
            break
    return predecessor

def find_rightmost(node):
    "
    Find the rightmost (largest) node starting from the given node.
    "
    while node.right:
        node = node.right
    return node

5: R-eview

Review the code by running specific example(s) and recording values (watchlist) of your code's variables along the way.

  • Ensure correct in-order predecessor identification in various configurations, especially where nodes do not have a left subtree.

6: E-valuate

Evaluate the performance of your algorithm and state any strong/weak or future potential work.

  • Time Complexity: O(h) where h is the height of the tree. This ensures efficient traversal up to the root or down to a leaf, depending on the node's position.
  • Space Complexity: O(1) as it only requires maintaining a few pointers without additional structures.