Stack using Queues
Implement a last in first out (LIFO) stack using only two queues. The implemented stack should support push, top, pop and empty. void push(int x) pushes element x to the top. int pop() removes and returns the top element. int top() returns the top element. boolean empty() returns true if the stack is empty. Each operation must only use standard queue operations (enqueue to back, dequeue from front, size, isEmpty).
- 1 <= x <= 9
- At most 100 calls to push, pop, top, and empty
- All calls to pop and top are valid
push(1), push(2), top(), pop(), empty()2, 2, falsepush(3), pop(), push(5), top()3, 5This is the mirror image of Queue using Stacks, and it pays to state both structures plainly first. A queue is a line: you join at the back (enqueue) and leave from the front (dequeue) — first in, first out. A stack is a pile: you add and remove from the same top — last in, first out. We're given only queues and must behave like a stack. So the element we must serve first is the newest, but a queue always hands back its oldest. The gap between "newest" and "what the queue gives me" is the whole problem.
A queue will only ever return whatever sits at its front. So instead of fighting that, arrange for the most recently pushed element to be the front. When a new value arrives, enqueue it at the back as usual — then immediately rotate every older element around behind it. Concretely: if there were N elements already, dequeue them one at a time from the front and re-enqueue them at the back, N times. Each old element loops from front to back, and when the loop finishes the newcomer — which started at the back — has been carried all the way to the front. Now the queue's natural front-dequeue is stack order.
This means push does the heavy lifting and pop/top become trivial — they just read the front, which we've already made correct.
from collections import deque
class MyStack:
def __init__(self):
self.q = deque()
def push(self, x):
self.q.append(x) # newcomer enters at the back
for _ in range(len(self.q) - 1): # rotate the OLDER elements behind it
self.q.append(self.q.popleft())
# now x is at the front
def pop(self):
return self.q.popleft() # front is the newest → stack top
def top(self):
return self.q[0]
def empty(self):
return not self.qlen(q) - 1 times, not len(q). You want to move only the elements that were there before the new one — the newcomer itself must stay put at the front. Rotate one time too many and the newcomer loops back to the rear, breaking the ordering; one too few and an old element is left blocking the front. Since we append the newcomer first, the count of older elements is exactly len(q) - 1.push(1) → append: [1]. Rotate len-1 = 0 times. Queue [1] (front 1).push(2) → append: [1, 2]. Rotate 1 time: dequeue 1, enqueue 1 → [2, 1] (front 2, the newest).push(3) → append: [2, 1, 3]. Rotate 2 times: move 2 to back → [1, 3, 2], move 1 to back → [3, 2, 1] (front 3).top() → read front → 3, the last pushed. pop() → remove front → 3. Queue [2, 1].pop() → 2. empty() → false (1 remains). Perfect LIFO out of a FIFO structure.Here the expense lands on push — each one rotates up to N elements, so push is O(N) — while pop and top are O(1). Contrast Queue using Stacks, which pushed cheaply and paid an amortized cost on pop. That's the real lesson of this pair: when you simulate one ordering with its opposite, someone pays for the reversal — your only choice is which operation eats the cost. Pick based on which call your workload does more often: rotate-on-push (this design) if you pop far more than you push, or push cheaply and defer if the reverse. Recognizing that the cost is movable, not removable, is the transferable idea.
Circular Queue Rotation for LIFO behavior
The Front-Loading Insight
When pushing a new element, it goes to the back. To make it the top, we rotate all existing elements around it until the new element reaches the front.
Design Trade-off
By doing the work during Push, we keep Pop and Peek extremely fast (O(1)).