BST Inorder Predecessor in DSA Javascript - Time & Space Complexity
We want to understand how long it takes to find the inorder predecessor in a Binary Search Tree (BST).
Specifically, how the time grows as the tree gets bigger.
Analyze the time complexity of the following code snippet.
function inorderPredecessor(root, node) {
if (node.left) {
let pred = node.left;
while (pred.right) {
pred = pred.right;
}
return pred;
}
let pred = null;
let curr = root;
while (curr) {
if (node.val > curr.val) {
pred = curr;
curr = curr.right;
} else {
curr = curr.left;
}
}
return pred;
}
This code finds the inorder predecessor of a given node in a BST by checking left subtree or ancestors.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Traversing down the tree nodes using while loops.
- How many times: At most, it moves down the height of the tree twice: once to find the rightmost node in left subtree, or once to find the ancestor.
As the tree grows taller, the number of steps to find the predecessor grows roughly with the tree height.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | Up to about 3-4 steps (tree height ~3-4) |
| 100 | Up to about 7 steps (tree height ~7) |
| 1000 | Up to about 10 steps (tree height ~10) |
Pattern observation: The steps grow slowly as the tree height grows, not directly with total nodes.
Time Complexity: O(h)
This means the time depends on the height of the tree, which is how deep it is from root to leaf.
[X] Wrong: "Finding the inorder predecessor always takes time proportional to the number of nodes (n)."
[OK] Correct: We only move down the tree height, not all nodes, so time depends on height (h), not total nodes (n).
Understanding this helps you explain how tree shape affects search times, a key skill for working with BSTs and similar structures.
"What if the BST is balanced versus completely unbalanced? How would the time complexity change?"
Practice
inorder predecessor of a node in a Binary Search Tree (BST)?Solution
Step 1: Understand BST ordering
In a BST, left children are smaller and right children are larger than the node.Step 2: Define inorder predecessor
The inorder predecessor is the node visited just before the current node in an inorder traversal, which means it has the largest value smaller than the current node.Final Answer:
The node with the largest value smaller than the given node -> Option AQuick Check:
Inorder predecessor = largest smaller value [OK]
- Confusing predecessor with successor
- Thinking predecessor is always left child
- Assuming predecessor is the root node
Solution
Step 1: Check function purpose and parameters
The function should find the inorder predecessor given the BST root and the target node.Step 2: Match signature to purpose
function findInorderPredecessor(root, node) {} correctly usesrootandnodeas parameters and names the function appropriately.Final Answer:
function findInorderPredecessor(root, node) {} -> Option CQuick Check:
Correct function name and parameters [OK]
- Using successor function name instead of predecessor
- Swapping parameter order
- Missing root parameter
20
/ \
10 30
\ \
15 40
Solution
Step 1: Locate node 15 and check left subtree
Node 15 has no left child, so we look upwards to find the largest smaller ancestor.Step 2: Find largest smaller ancestor
Node 10 is the parent of 15 and smaller than 15, so 10 is the inorder predecessor.Final Answer:
10 -> Option AQuick Check:
Largest smaller value than 15 is 10 [OK]
- Choosing the node itself as predecessor
- Choosing the parent if it is larger
- Confusing successor with predecessor
function findInorderPredecessor(root, node) {
if (node.left) {
let temp = node.left;
while (temp.right) {
temp = temp.right;
}
return temp;
}
let predecessor = null;
let current = root;
while (current) {
if (node.val > current.val) {
predecessor = current;
current = current.right;
} else {
current = current.left;
}
}
return predecessor;
}
Solution
Step 1: Analyze code logic for predecessor
The code correctly finds predecessor if node has left child or searches ancestors otherwise.Step 2: Identify missing validation
Code does not verify if the given node actually exists in the BST, which can cause incorrect results or errors.Final Answer:
It does not check if node exists in the BST -> Option BQuick Check:
Missing node existence check [OK]
- Assuming node is always in BST
- Confusing left child check logic
- Ignoring null return possibility
40
/ \
20 60
/ \ / \
10 30 50 70
/
25
Which node is the inorder predecessor of 25, and why?Solution
Step 1: Check if node 25 has left child
Node 25 has no left child, so we look for the largest ancestor smaller than 25.Step 2: Find largest smaller ancestor
Ancestors of 25 are 30, 20, and 40. Among these, 30 is the parent of 25 and the largest smaller ancestor is 20, but since 25 is in the left subtree of 30, the inorder predecessor is 30's left subtree's rightmost node or the parent if no left subtree exists. Here, 25 is left child of 30, so predecessor is 20.Final Answer:
20, because it is the largest smaller ancestor -> Option DQuick Check:
Largest smaller ancestor = 20 [OK]
- Choosing parent node 30 incorrectly
- Thinking no predecessor exists
- Choosing smallest smaller node instead of largest
Ready to prove it?
Pass the test and this pattern moves unknown
