Implement Queue using Stack
Implement FIFO push/pop/peek using only stack operations.
Intuition
Two stacks: inbox collects pushes; outbox serves pops. Pouring inbox into outbox reverses order once — oldest lands on top. Only pour when outbox is empty, and each element makes the trip exactly once → amortized O(1).
The mirror design problem, and the more elegant answer: pouring one stack into another reverses the order, so two stacks give FIFO. The key is pouring only when the outbox is empty — that makes the cost amortised O(1), because each element is moved across exactly once in its lifetime. Amortised analysis is the point of this question.
Approach
Two one-way stacks
push → inbox. pop/peek → outbox top. Direction of each stack never changes.
Lazy transfer
Only when outbox runs dry, pour all of inbox into it. Elements already in outbox stay correctly ordered.
Amortized analysis
Each element is pushed twice and popped twice total, ever — O(1) average per operation.
Solution & live demo
Common pitfalls
Pouring on every operation
def _shift(self):
while self.inbox:
self.outbox.append(self.inbox.pop())def _shift(self):
if not self.outbox:
while self.inbox:
self.outbox.append(self.inbox.pop())Pouring while the outbox still holds items puts newer elements underneath older ones, destroying FIFO order. The guard is what keeps the two halves consistent — and what makes each element cross only once.
Pouring back and forth on every call
# push: move outbox -> inbox, append, move back
# push: append to inbox only; pour lazily on pop/peek
That makes every operation O(n) instead of amortised O(1). Elements should sit in the inbox until someone actually needs to read from the front.
Checking only one stack for emptiness
return not self.outbox
return not self.inbox and not self.outbox
Elements may be waiting in the inbox that haven't been poured yet, so an empty outbox says nothing about the queue as a whole. The queue is empty only when both halves are.
Edge cases
Serve outbox; inbox must NOT be poured on top (would reorder).
Same rule as pop minus removal — always outbox top after a lazy pour.