Implement a last-in-first-out (LIFO) stack using only two queues. The implemented stack should support all the functions of a normal stack (push, top, pop, and empty).
Implement the MyStack class:
void push(int x) Pushes element x to the top of the stack.int pop() Removes the element on the top of the stack and returns it.int top() Returns the element on the top of the stack.boolean empty() Returns true if the stack is empty, false otherwise.Notes:
push to back, peek/pop from front, size and is empty operations are valid.["MyStack", "push", "push", "top", "pop", "empty"] [[], [1], [2], [], [], []]
MyStack myStack = new MyStack();myStack.push(1);myStack.push(2);myStack.top(); // return 2myStack.pop(); // return 2myStack.empty(); // return False1 <= x <= 9100 calls will be made to push, pop, top, and empty.pop and top are valid.Can you implement the stack using only one queue?
The pop and top operations drain all but one element from the active queue, requiring dequeue operations. push simply appends to the active queue in .
The two queues together hold all n elements at any point in time.
This approach uses two queues and alternates which one is "active" — all elements are kept in one queue at a time, and new elements are always appended to whichever queue is currently active. For pop and top, we drain all but the last element from the active queue into the inactive one, which effectively reverses their roles, and then dequeue the final element (the stack top).
pop and top iterate through n-1 elements to reach the last one, giving . Swapping queue references is . push is a single enqueue, .
All n elements are distributed across the two queues at any time.
This approach keeps push simple — new elements always go to the back of queue1. The work is deferred to pop and top: we drain all but the last element from queue1 into queue2, then dequeue the remaining element (the stack top), and finally swap the two queues so queue1 always remains the primary queue.
push moves all existing n-1 elements from queue1 to queue2, so it costs . pop and top simply dequeue/peek the front of queue1, which is .
All n elements are stored across the two queues at any time.
This approach shifts the cost to push so that pop and top become . On each push, the new element is added to the back of queue2, then all elements from queue1 are moved into queue2 (so the new element ends up at the front), and the two queues are swapped — making queue1 always ordered with the most recently pushed element at the front.
push rotates n-1 existing elements through the queue, costing . pop and top operate directly on the front element in .
A single queue holds all n elements.
This is the one-queue version of Solution 3's push-heavy strategy. On each push, after appending the new element to the back of the queue, we rotate all the previously existing elements to the back — cycling them through the front — so the newly pushed element ends up at the front. This keeps the stack top always at the head of the queue, making pop and top .
pop rotates n-1 elements through the queue, costing . push is a single enqueue plus assignment in . top simply returns the cached top_element in .
A single queue holds all n elements, plus one variable for top_element.
This approach also uses a single queue but trades an pop for top by tracking the top element explicitly in top_element. push is — just enqueue and update top_element. For pop, we rotate n-1 elements to bring the last one to the front, updating top_element along the way so it always reflects the new top after the pop.
| Approach | Rating | Time Complexity | Space Complexity | Advantages | Disadvantages |
|---|---|---|---|---|---|
| Two queues, alternating active queue | for pop/top, for push | Simple to follow; no queue swapping needed | ⚠️ Requires two queues; alternating logic is error-prone | ||
| Two queues with one active queue and swapping | for pop/top, for push | Cleaner than Solution 1 by always using queue1 as primary | ⚠️ Still requires two queues with reads | ||
| Push-heavy approach with two queues | for push, for pop/top | pop and top are ideal for read-heavy workloads | ⚠️ Requires two queues; every push is | ||
| Push-heavy approach with one queue | for push, for pop/top | Meets the follow-up with one queue; reads via front-of-queue invariant | Every push rotates all existing elements, costing | ||
| Pop-heavy approach with one queue | for pop, for push/top | Meets the follow-up; push and top via cached top_element | Every pop rotates all elements, costing |
| Approach | push | pop | top | empty |
|---|---|---|---|---|
| Standard Stack | ||||
| Two queues, alternating active queue | ⚠️ | ⚠️ | ||
| Two queues with one active queue and swapping | ⚠️ | ⚠️ | ||
| Push-heavy approach with two queues | ⚠️ | |||
| Push-heavy approach with one queue | ⚠️ | |||
| Pop-heavy approach with one queue | ⚠️ |
| Approach | push | pop | top | empty | Total |
|---|---|---|---|---|---|
| Standard Stack | |||||
| Two queues, alternating active queue | ℹ️ | ℹ️ | |||
| Two queues with one active queue and swapping | ℹ️ | ℹ️ | |||
| Push-heavy approach with two queues | ℹ️ | ||||
| Push-heavy approach with one queue | ℹ️ | ||||
| Pop-heavy approach with one queue | ℹ️ |
The optimal approach for this problem is Solution 4: Push-heavy approach with one queue, which achieves for push, for pop/top time complexity and space complexity. It satisfies the follow-up's single-queue constraint and keeps reads efficient by maintaining the stack top at the front of the queue via a rotation on each push. Solutions marked with ⚠️ in the first table do not meet the follow-up requirement and are not recommended.