BST Inorder Successor in DSA Go - Time & Space Complexity
We want to understand how long it takes to find the next bigger value in a Binary Search Tree (BST) after a given node.
How does the time needed grow as the tree gets bigger?
Analyze the time complexity of the following code snippet.
// Find the inorder successor of a node in BST
func inorderSuccessor(root, p *TreeNode) *TreeNode {
var successor *TreeNode
current := root
for current != nil {
if p.Val < current.Val {
successor = current
current = current.Left
} else {
current = current.Right
}
}
return successor
}
This code finds the next larger node after p in a BST by walking down from the root.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The while loop that moves down the tree nodes.
- How many times: At most once per tree level, moving left or right.
As the tree grows taller, the number of steps to find the successor grows roughly with the height.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | Up to 4 steps (height ~4) |
| 100 | Up to 7 steps (height ~7) |
| 1000 | Up to 10 steps (height ~10) |
Pattern observation: The steps grow slowly as the tree height grows, not with total nodes.
Time Complexity: O(h)
This means the time depends on the tree height, which is the number of levels from root to leaf.
[X] Wrong: "Finding the successor always takes time proportional to the total number of nodes (n)."
[OK] Correct: The search moves down one path only, not the whole tree, so it depends on height, not total nodes.
Knowing how tree height affects search time helps you explain and optimize tree operations clearly in interviews.
"What if the BST is balanced vs completely unbalanced? How would the time complexity change?"
Practice
Solution
Step 1: Understand inorder traversal order
Inorder traversal visits nodes in ascending order of their keys in a BST.Step 2: Define inorder successor
The inorder successor of a node is the next node visited after it in inorder traversal, which is the smallest node with a key greater than the current node's key.Final Answer:
The node with the smallest key greater than the given node's key -> Option BQuick Check:
Inorder successor = next larger node [OK]
- Confusing successor with predecessor
- Thinking successor is always right child
- Assuming successor is parent node
Solution
Step 1: Analyze function parameters
To find the inorder successor, we need the BST root and the target node pointer, both as pointers to Node structs.Step 2: Check return type
The function should return a pointer to the successor node, so return type is *Node.Final Answer:
func inorderSuccessor(root *Node, p *Node) *Node -> Option AQuick Check:
Function needs root and target node pointers, returns node pointer [OK]
- Passing nodes by value instead of pointer
- Returning int instead of node pointer
- Missing root parameter
type Node struct {
Val int
Left *Node
Right *Node
}
func inorderSuccessor(root, p *Node) *Node {
var successor *Node
for root != nil {
if p.Val < root.Val {
successor = root
root = root.Left
} else {
root = root.Right
}
}
return successor
}
// BST structure:
// 20
// / \
// 10 30
// \
// 15
p := &Node{Val: 15}
succ := inorderSuccessor(root, p)
if succ != nil {
fmt.Println(succ.Val)
} else {
fmt.Println("nil")
}Solution
Step 1: Trace inorderSuccessor function for p=15
Start at root=20: 15 < 20, successor=20, move left to 10. At 10: 15 >= 10, move right to 15. At 15: 15 >= 15, move right (nil). Loop ends.Step 2: Return successor node
Successor is 20, so succ.Val = 20 is printed.Final Answer:
20 -> Option AQuick Check:
Next bigger node after 15 is 20 [OK]
- Returning p itself as successor
- Returning nil when right subtree is empty
- Confusing successor with predecessor
func inorderSuccessor(root, p *Node) *Node {
if p.Right != nil {
curr := p.Right
for curr.Left != nil {
curr = curr.Left
}
return curr
}
var successor *Node
for root != nil {
if p.Val < root.Val {
successor = root
root = root.Left
} else {
root = root.Right
}
}
return successor
}Solution
Step 1: Understand the logic for successor search
The code tries to find successor by checking right subtree or walking from root to find successor.Step 2: Identify the bug in root traversal
The code assumes root is the BST root, but if root is not the actual BST root or p is not reachable from root, the successor found may be incorrect.Final Answer:
It assumes root is always the BST root, which may not be true -> Option DQuick Check:
Root must be BST root to find correct successor [OK]
- Passing a root that is not the BST root
- Not checking if p.Right is nil before access
- Ignoring case when p has no right subtree
p efficiently using this parent pointer? Choose the correct approach.Solution
Step 1: Check if p has right child
If yes, successor is the leftmost node in p's right subtree.Step 2: If no right child, move up using parent pointer
Keep moving up until current node is left child of its parent; that parent is the successor.Final Answer:
If p has right child, successor is leftmost node in right subtree; else move up using parent until node is left child of its parent -> Option CQuick Check:
Use right subtree or climb parents to find successor [OK]
- Confusing left and right subtree roles
- Always returning parent as successor
- Performing full traversal instead of using parent pointer
Ready to prove it?
Pass the test and this pattern moves unknown
