Last Updated: March 29, 2026
We need to build a queue (FIFO: first in, first out) using only stacks (LIFO: last in, first out). The challenge is that these two data structures have opposite ordering. When you push elements 1, 2, 3 onto a stack, popping gives you 3, 2, 1. But a queue should give you 1, 2, 3 in the same order they went in.
So the real question is: how do we reverse the order of elements using stacks? The key insight is surprisingly simple. If you push elements onto one stack and then pop them all into a second stack, the order reverses. The element that was at the bottom of the first stack ends up on top of the second stack, which is exactly the element that should come out first in a queue.
The interesting part of this problem is not whether you can solve it, but how efficiently you can do it. There are two main strategies, and they differ in which operation pays the cost of transferring elements between stacks.
1 <= x <= 9 → The values are tiny, so there are no overflow concerns. This constraint is mostly about keeping examples simple.100 calls → With such a small number of operations, any approach will work performance-wise. But the follow-up asks us to think about amortized efficiency, which is the real learning goal.pop and peek calls are valid → We never need to handle the "queue is empty" edge case for these operations. This simplifies the code.The most intuitive approach is to keep the output stack always in the correct order so that pop and peek are instant. To do this, every time we push a new element, we rearrange everything so the oldest element stays on top of the main stack.
Here is the idea: we designate one stack as our "main" stack where elements are stored in queue order (oldest on top). When a new element arrives, we move everything from the main stack to a temporary helper stack, push the new element onto the now-empty main stack, and then move everything back. The new element ends up at the bottom, and the oldest element stays on top.
main (stores elements in queue order, oldest on top) and helper (temporary storage during push).main to helper. Push x onto main. Move all elements back from helper to main.main (the top is the oldest element).main (the top is the oldest element).main is empty.This approach works but every push rearranges the entire queue. What if we only rearranged when someone actually needs to dequeue?
Instead of doing all the work upfront during push, we can be lazy about it. The idea is to use two stacks with distinct roles: an input stack for pushing and an output stack for popping.
When we push, we just throw the element onto the input stack. No rearranging, no fuss. O(1).
When we pop or peek, we look at the output stack. If it has elements, the top is the oldest element, so we just pop from there. If the output stack is empty, we pour everything from the input stack into the output stack. This reversal puts the elements in FIFO order.
The genius of this approach is that each element is moved at most twice in its entire lifetime: once when it is pushed onto the input stack, and once when it is transferred to the output stack. So across n operations, the total work is O(n), making each operation amortized O(1).
Think about the lifecycle of a single element. It gets pushed onto the input stack once (O(1) work). At some later point, it gets popped from the input stack and pushed onto the output stack (O(1) work). Finally, it gets popped from the output stack (O(1) work). That is 3 operations total per element, regardless of how many other operations happen.
So even though a single pop call might trigger an O(n) transfer, that transfer handles all n elements at once. Those n elements will then be served by future pop calls in O(1) each, without needing another transfer. The expensive operation "pays forward" for many cheap future operations.
input (receives pushed elements) and output (serves pop/peek requests).