Implement a Stack Using Two Queues
Solve this Problempush(v), pop(), top(), isEmpty(), and size(). As with the array and linked-list versions, this takes a fixed sequence of operations and replays them, returning the result of every pop, top, isEmpty, and size call as an array.
A queue naturally hands back its oldest element first — the opposite of what a stack needs. Two classic techniques bridge that gap, and they're complementary rather than one strictly beating the other: rotate the queue after every push so the newest value ends up at the front (cheap pop, expensive push), or drain the queue down to just its last element whenever something needs to come off the top (cheap push, expensive pop). Neither approach avoids the reordering work a real stack never needs in the first place — they just disagree about which operation should pay for it.
Test Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
1 ≤ number of operations ≤ 12 - ◆
Each operation is one of push, pop, top, isEmpty, or size - ◆
0 ≤ pushed value ≤ 1000 - ◆
pop and top return -1 when the stack is empty - ◆
Only queue operations (enqueue at the back, dequeue from the front, peek the front) may be used to store elements — no direct indexing into the middle - ◆
This version replays a fixed sequence of operations and reports the result of every pop, top, isEmpty, and size call, in order (push has no return value)
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Push Costly — Rotate the Queue After Every Push
GoodKeep everything in a single queue. To push a value, enqueue it at the back like normal, then rotate the whole queue — dequeue from the front and immediately enqueue it at the back — exactly (size - 1) times. That walks every older element around to the back, one at a time, leaving the brand-new value sitting at the front. From then on, the queue's front is always the most recently pushed value, so pop and top are trivial O(1) reads from the front. The cost is pushed entirely onto push itself: it does O(size) work every time.
O(n) per push, O(1) per pop/topO(n)1class Solution {
2 public int[] stackOpsFromQueues(String[] ops, int[] args) {
3 Queue<Integer> q = new LinkedList<>();
4 List<Integer> results = new ArrayList<>();
5 for (int i = 0; i < ops.length; i++) {
6 String op = ops[i];
7 if (op.equals("push")) {
8 q.add(args[i]);
9 int rotations = q.size() - 1;
10 for (int r = 0; r < rotations; r++) {
11 q.add(q.poll());
12 }
13 } else if (op.equals("pop")) {
14 results.add(q.isEmpty() ? -1 : q.poll());
15 } else if (op.equals("top")) {
16 results.add(q.isEmpty() ? -1 : q.peek());
17 } else if (op.equals("isEmpty")) {
18 results.add(q.isEmpty() ? 1 : 0);
19 } else {
20 results.add(q.size());
21 }
22 }
23 int[] output = new int[results.size()];
24 for (int i = 0; i < results.size(); i++) output[i] = results.get(i);
25 return output;
26 }
27}Pop Costly — Two Queues, Transfer on Pop
OptimalThe complementary trade-off: keep push cheap instead of pop. Every push is a plain enqueue onto q1 — O(1), no rotation. All the work happens when something needs to come off the top: drain every element except the last from q1 into a second queue q2 (dequeue from q1, enqueue into q2), leaving only the most-recently-pushed value in q1 — dequeue that one as the answer, then swap the roles of q1 and q2 so the next push continues on the (now-repopulated) main queue. Tracking the most recent value in a separate variable, updated on every push, makes top() an O(1) read too instead of repeating the drain-and-restore dance.
O(1) per push, O(n) per popO(n)1class Solution {
2 public int[] stackOpsFromQueues(String[] ops, int[] args) {
3 Queue<Integer> q1 = new LinkedList<>();
4 Queue<Integer> q2 = new LinkedList<>();
5 int topVal = -1;
6 List<Integer> results = new ArrayList<>();
7 for (int i = 0; i < ops.length; i++) {
8 String op = ops[i];
9 if (op.equals("push")) {
10 q1.add(args[i]);
11 topVal = args[i];
12 } else if (op.equals("pop")) {
13 if (q1.isEmpty()) {
14 results.add(-1);
15 } else {
16 while (q1.size() > 1) {
17 topVal = q1.poll();
18 q2.add(topVal);
19 }
20 results.add(q1.poll());
21 Queue<Integer> tmp = q1;
22 q1 = q2;
23 q2 = tmp;
24 }
25 } else if (op.equals("top")) {
26 results.add(q1.isEmpty() ? -1 : topVal);
27 } else if (op.equals("isEmpty")) {
28 results.add(q1.isEmpty() ? 1 : 0);
29 } else {
30 results.add(q1.size());
31 }
32 }
33 int[] output = new int[results.size()];
34 for (int i = 0; i < results.size(); i++) output[i] = results.get(i);
35 return output;
36 }
37}