const solve = (nums) => { let left = 0, right = nums.length - 1; while (left < right) { const sum = nums[left] + nums[right]; if (sum === target) return [left, right]; }}
Problem Walkthrough

Implement Stack Using Queues — LeetCode 225 Walkthrough

LeetCode #225 is the mirror of Queue Using Stacks — build a LIFO stack from FIFO queues using rotation. The costly-push approach gives O(1) pop and top.

6 min read|

Build LIFO from FIFO — rotate the queue on every push

Costly-push approach gives O(1) pop and top for typical stack usage

Implement Stack Using Queues: LeetCode 225

Implement Stack Using Queues (#225) is the mirror image of Implement Queue Using Stacks (#232). Where #232 asks you to build FIFO from LIFO, this problem flips the challenge: build LIFO from FIFO. Both problems test the same fundamental concept — composing one abstract data type from another — and solving both demonstrates you understand the relationship between stacks and queues at a structural level.

The implement stack using queues leetcode problem asks you to create a class that supports push, pop, top, and empty, using only standard queue operations: enqueue (push to back), dequeue (pop from front), peek (front), and size. You cannot use a deque or any stack-like shortcut.

This is an Easy-rated problem, but it carries outsized interview value. Interviewers use it to test whether you can think about data structure composition — not just use built-in stacks, but reason about how they work internally.

Understanding the Problem

You need to implement four operations: push(x) adds element x to the top of the stack, pop() removes and returns the top element, top() returns the top element without removing it, and empty() returns whether the stack is empty. The constraint is that you may only use a queue as your underlying data structure.

The core challenge is that a queue is FIFO — the first element you add is the first one you remove. A stack is LIFO — the last element you add is the first one you remove. You need to bridge this gap so that the most recently pushed element is always accessible first.

There are two classic approaches: make push expensive (costly push) or make pop expensive (costly pop). Both are valid, but they have different trade-offs that matter in interviews.

Approach 1: Costly Push — O(n) Push, O(1) Pop

The costly-push approach is the more elegant of the two. When you push a new element, enqueue it to the back of the queue, then rotate all previous elements to the back by dequeueing and re-enqueueing them one by one. After this rotation, the newly pushed element sits at the front of the queue — exactly where a stack's top element should be.

With this approach, push is O(n) because you rotate n-1 existing elements on every push. But pop and top are both O(1) — you simply dequeue from the front. The empty operation is O(1) as well, checking if the queue is empty.

The space complexity is O(n) for storing all elements. You only need a single queue, which is a nice bonus over approaches that require two queues.

  1. 1Create a single queue
  2. 2push(x): Enqueue x, then dequeue and re-enqueue n-1 elements (where n is the current size)
  3. 3pop(): Dequeue from the front — this is the most recently pushed element
  4. 4top(): Peek at the front of the queue
  5. 5empty(): Return whether the queue is empty
💡

Pro Tip

The costly-push approach: after enqueue, rotate the queue by dequeueing and re-enqueueing n-1 times. This puts the new element at the front, giving O(1) pop.

Approach 2: Costly Pop — O(1) Push, O(n) Pop

The costly-pop approach takes the opposite trade-off. Push is simple — just enqueue the element to the back of the queue in O(1). The work happens when you pop: dequeue n-1 elements and re-enqueue them, then dequeue the last remaining element, which is the most recently pushed one.

Pop is O(n) because you move n-1 elements out and back in. Top also requires O(n) work unless you maintain a separate variable tracking the last pushed element. Push is O(1), and empty is O(1).

This approach also works with a single queue, but the performance profile is inverted compared to costly push. Which one you choose depends on the expected usage pattern of the stack.

  • push(x): Enqueue x to back — O(1)
  • pop(): Dequeue n-1 elements and re-enqueue, then dequeue the last — O(n)
  • top(): Same as pop but re-enqueue the last element too, or track top separately — O(n) or O(1) with variable
  • empty(): Check if queue is empty — O(1)

Which Approach Is Better for Interviews

The costly-push approach is generally preferred. In typical stack usage, pop and top are called more frequently than push. Making pop O(1) optimizes the common case. Additionally, the costly-push version is cleaner to implement because pop and top are trivial one-liners.

From an interviewer's perspective, the costly-push approach shows you can reason about amortized usage patterns. You are deliberately making one operation slower to speed up the operations that matter most. This kind of trade-off reasoning is exactly what interviewers want to see.

That said, you should mention both approaches and explain the trade-off. Demonstrating awareness of alternatives shows depth. Implement the costly-push version, but acknowledge that if pushes far outnumber pops, the costly-pop approach would be the better choice.

⚠️

Interview Advice

Most interviewers prefer the costly-push approach because O(1) pop matches typical stack usage patterns — mention both but implement the one that optimizes the most common operation.

Edge Cases to Consider

Popping a single-element stack is straightforward in both approaches. With costly push, the single element is already at the front, so you dequeue it. With costly pop, there are no elements to rotate, so you just dequeue the only element directly.

Consecutive pushes without any pops work correctly with costly push — each push rotates all previous elements. After pushing 1, 2, 3, the queue front-to-back order is [3, 2, 1], exactly matching stack order.

The empty check is trivial in both approaches since it maps directly to the underlying queue's empty check. Always verify empty returns true after popping all elements and false after any push.

  • Single element pop: No rotation needed in either approach
  • Consecutive pushes: Costly push maintains correct LIFO order after each push
  • Empty after pop-all: Must return true once all elements are removed
  • Push after empty: Stack resets cleanly — push works the same on empty or non-empty queue

What This Problem Teaches

Implement Stack Using Queues is fundamentally about ADT composition — proving that one abstract data type can simulate another. This is the same principle behind Queue Using Stacks (#232), and solving both problems together solidifies your understanding of how LIFO and FIFO relate to each other.

The rotation technique (dequeue and re-enqueue to move elements) is a general-purpose queue manipulation pattern. You will see it reappear in circular buffer problems and round-robin scheduling questions. Internalizing this pattern pays dividends beyond just this problem.

If you found this walkthrough helpful, review it alongside LeetCode #232 Queue Using Stacks and #155 Min Stack on YeetCode. The implement stack using queues leetcode problem is a perfect flashcard candidate — the rotation trick is simple but easy to blank on during an interview.

ℹ️

Mirror Problem

Implement Stack Using Queues (#225) is the mirror of Queue Using Stacks (#232) — solving both demonstrates you understand the fundamental relationship between LIFO and FIFO.

Ready to master algorithm patterns?

YeetCode flashcards help you build pattern recognition through active recall and spaced repetition.

Start practicing now