BST Iterator Design in DSA C++ - Time & Space Complexity
We want to understand how fast the BST Iterator works when moving through a binary search tree.
Specifically, how the time to get the next smallest element changes as the tree grows.
Analyze the time complexity of the following BST Iterator code snippet.
class BSTIterator {
stack<TreeNode*> st;
public:
BSTIterator(TreeNode* root) {
while (root) {
st.push(root);
root = root->left;
}
}
int next() {
TreeNode* node = st.top(); st.pop();
int val = node->val;
node = node->right;
while (node) {
st.push(node);
node = node->left;
}
return val;
}
bool hasNext() {
return !st.empty();
}
};
This code creates an iterator that returns the next smallest value in a BST by using a stack to track nodes.
Look at what repeats when calling next():
- Primary operation: Pushing and popping nodes from the stack while traversing left children.
- How many times: Each node is pushed and popped exactly once during the entire iteration.
As the tree size n grows, each node is processed once.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 pushes and 10 pops total |
| 100 | About 100 pushes and 100 pops total |
| 1000 | About 1000 pushes and 1000 pops total |
Pattern observation: The total work grows linearly with the number of nodes in the tree.
Time Complexity: O(1) amortized per next()
This means each call to next() takes constant time on average, even though some calls do more work.
[X] Wrong: "Each call to next() always takes O(h) time, where h is tree height."
[OK] Correct: While some calls do take O(h) time, the total work over all nodes is spread out, so average time per call is O(1).
Understanding this iterator's time complexity shows you can analyze average work over many operations, a key skill in coding interviews.
"What if we changed the iterator to store all nodes in a sorted list upfront? How would the time complexity of next() change?"
Practice
Solution
Step 1: Understand BST Iterator functionality
A BST Iterator is designed to traverse the tree in sorted order, typically ascending, without using recursion explicitly.Step 2: Identify the main purpose
It provides a way to get the next smallest element efficiently, which matches To traverse the BST in ascending order without recursion.Final Answer:
To traverse the BST in ascending order without recursion -> Option AQuick Check:
BST Iterator = In-order traversal without recursion [OK]
- Confusing iterator with insertion or deletion operations
- Thinking it balances the tree automatically
- Assuming it uses recursion internally
Solution
Step 1: Identify the data type stored in the stack
The BST Iterator stores pointers to tree nodes to traverse the tree efficiently, so the stack should hold TreeNode pointers.Step 2: Match the correct syntax
stack s; uses stack which is correct. stack<int> s; uses int, which is incorrect. stack<TreeNode> s; uses TreeNode by value, which is inefficient. stack s; uses Node*, which is undefined here.Final Answer:
stack s; -> Option DQuick Check:
Stack stores pointers to TreeNode [OK]
- Using stack of int instead of TreeNode*
- Using stack of TreeNode by value causing copies
- Using undefined Node* type
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class BSTIterator {
stack s;
void pushLeft(TreeNode* node) {
while (node) {
s.push(node);
node = node->left;
}
}
public:
BSTIterator(TreeNode* root) { pushLeft(root); }
int next() {
TreeNode* node = s.top(); s.pop();
pushLeft(node->right);
return node->val;
}
bool hasNext() { return !s.empty(); }
};
// BST structure:
// 7
// / \
// 3 15
// / \
// 9 20
BSTIterator it(root);
while(it.hasNext()) {
cout << it.next() << " ";
}Solution
Step 1: Understand the BST structure and in-order traversal
The BST is: 7 / \ 3 15 / \ 9 20 In-order traversal visits nodes in ascending order: 3, 7, 9, 15, 20.Step 2: Trace the iterator's next() calls
Iterator pushes left nodes first, so initial stack: 7, 3 (top). Calls to next() pop 3, then 7, then push left of 7's right (15), then 9, then 15, then 20. Output sequence matches 3 7 9 15 20.Final Answer:
3 7 9 15 20 -> Option CQuick Check:
In-order traversal = 3 7 9 15 20 [OK]
- Confusing pre-order or post-order traversal output
- Not pushing left children correctly
- Misunderstanding stack top element order
int next() {
TreeNode* node = s.top();
s.pop();
pushLeft(node->left); // Bug here
return node->val;
}Solution
Step 1: Analyze the next() method logic
After popping the current node, the iterator should push all left children of the right subtree to continue in-order traversal.Step 2: Identify the incorrect call
The code incorrectly calls pushLeft(node->left), which revisits the left subtree already processed. It should call pushLeft(node->right) to process the right subtree.Final Answer:
Change pushLeft(node->left) to pushLeft(node->right) -> Option BQuick Check:
Push left of right subtree after pop [OK]
- Pushing left subtree again causing infinite loop
- Removing pushLeft call causing incomplete traversal
- Incorrect pop syntax causing compile error
peek() which returns the next smallest element without advancing the iterator. How would you modify the existing BST Iterator design to support peek() efficiently?Solution
Step 1: Understand peek() requirement
peek() should return next smallest element without moving the iterator forward, so it must remember the next element.Step 2: Modify iterator to store next element
By storing the next smallest element in a variable during next(), peek() can return this stored value without popping or changing the stack.Step 3: Evaluate other options
Using an extra stack or precomputing all elements wastes space or changes iterator behavior. Modifying next() to not pop breaks standard iteration.Final Answer:
Store the next smallest element in a variable during next() and return it in peek() -> Option AQuick Check:
Cache next element for peek() [OK]
- Precomputing all elements wastes memory
- Changing next() behavior breaks iteration
- Using extra stack complicates design unnecessarily
Ready to prove it?
Pass the test and this pattern moves unknown
