class BSTIterator:
def __init__(self, root):
self.stack = []
self._push_left(root)
def _push_left(self, node):
while node:
self.stack.append(node)
node = node.left
def next(self):
node = self.stack.pop()
val = node.val
if node.right:
self._push_left(node.right)
return val
def hasNext(self):
return len(self.stack) > 0
class BSTIterator {
stack<TreeNode*> st;
public:
BSTIterator(TreeNode* root) {
pushLeft(root);
}
void pushLeft(TreeNode* node) {
while (node) {
st.push(node);
node = node->left;
}
}
int next() {
TreeNode* node = st.top(); st.pop();
if (node->right) pushLeft(node->right);
return node->val;
}
bool hasNext() {
return !st.empty();
}
};
class BSTIterator {
private Stack<TreeNode> stack = new Stack<>();
public BSTIterator(TreeNode root) {
pushLeft(root);
}
private void pushLeft(TreeNode node) {
while (node != null) {
stack.push(node);
node = node.left;
}
}
public int next() {
TreeNode node = stack.pop();
if (node.right != null) {
pushLeft(node.right);
}
return node.val;
}
public boolean hasNext() {
return !stack.isEmpty();
}
}
var BSTIterator = function(root) {
this.stack = [];
this._pushLeft = function(node) {
while (node) {
this.stack.push(node);
node = node.left;
}
};
this._pushLeft(root);
};
BSTIterator.prototype.next = function() {
let node = this.stack.pop();
if (node.right) {
this._pushLeft(node.right);
}
return node.val;
};
BSTIterator.prototype.hasNext = function() {
return this.stack.length > 0;
};
You are given the root node of a binary search tree (BST) and asked to design an iterator over its elements. Your iterator should return the next smallest number in the BST each time you call next()
, and indicate whether there is a next number with hasNext()
.
BSTIterator
class with the following methods:BSTIterator(TreeNode root)
: Initializes the iterator with the root node of the BST.int next()
: Returns the next smallest number in the BST.boolean hasNext()
: Returns true if there exists a next number; otherwise, false.next()
and hasNext()
should run in average O(1) time.next()
will always be called if hasNext()
returns true.
To solve this problem, we need to simulate an in-order traversal of a BST, which naturally yields nodes in ascending order. A brute-force approach might be to traverse the entire tree at the start, store all values in a list, and then iterate through that list. While this would make next()
and hasNext()
trivial, it would use O(n) extra memory, which violates the O(h) space constraint.
Instead, we should only store enough information to know what the next smallest element is, without visiting the entire tree upfront. This leads us to use a stack to keep track of the path to the next node. Each time we need the next smallest element, we can pop from the stack, and if the popped node has a right child, we process its leftmost descendants. This way, we only use O(h) space and efficiently find the next element.
The core idea is to simulate the in-order traversal iteratively using a stack:
Why a stack? The stack keeps track of the path from the root to the current node, allowing us to efficiently backtrack and find the next smallest element without traversing nodes multiple times.
next()
and hasNext()
are O(1) on average.Consider the BST:
7 / \ 3 15 / \ 9 20Initialization:
Brute-force approach:
next()
and hasNext()
.next()
and hasNext()
. Each node is pushed and popped once, so total O(n) over all operations.The use of a stack ensures we never exceed O(h) space, and the amortized cost per operation is constant.
The BST Iterator problem is elegantly solved by simulating in-order traversal with a stack, ensuring that each call to next()
and hasNext()
is efficient and uses minimal space. The key insight is to only maintain the path to the next smallest node, rather than all nodes, thus satisfying both the time and space constraints. This approach is both practical and widely applicable when you need to iterate through BSTs in sorted order.