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.Example 1:
Input: ["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
Output: [null, null, null, 2, 2, false]Explanation:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // return 2
myStack.pop(); // return 2
myStack.empty(); // return False
Constraints:
1 <= x <= 9100 calls will be made to push, pop, top, and empty.pop and top are valid.Follow-up: Can you implement the stack using only one queue?
Before attempting this problem, you should be comfortable with:
A stack follows Last-In-First-Out (LIFO) order, but a queue follows First-In-First-Out (FIFO). To simulate a stack using queues, we need to reverse the order of elements on each push.
The idea is to use two queues: when pushing a new element, we add it to the empty second queue, then move all elements from the first queue behind it. This places the newest element at the front, ready to be popped first.
After rearranging, we swap the two queues so the main queue always has elements in stack order.
q1 and q2.x to q2, then move all elements from q1 to q2 one by one. Finally, swap q1 and q2.q1.q1 without removing it.true if q1 is empty.class MyStack:
def __init__(self):
self.q1 = deque()
self.q2 = deque()
def push(self, x: int) -> None:
self.q2.append(x)
while self.q1:
self.q2.append(self.q1.popleft())
self.q1, self.q2 = self.q2, self.q1
def pop(self) -> int:
return self.q1.popleft()
def top(self) -> int:
return self.q1[0]
def empty(self) -> bool:
return len(self.q1) == 0We can achieve the same result with just one queue. The trick is to rotate the queue after each push so the newest element moves to the front.
When we add an element, we push it to the back of the queue, then dequeue and re-enqueue all the elements that were already there. This effectively moves the new element to the front.
This approach uses less space than two queues while maintaining the same time complexity for push operations.
q.x to the back of q. Then, rotate the queue by removing and re-adding elements size - 1 times. This moves x to the front.q.q without removing it.true if q is empty.class MyStack:
def __init__(self):
self.q = deque()
def push(self, x: int) -> None:
self.q.append(x)
for _ in range(len(self.q) - 1):
self.q.append(self.q.popleft())
def pop(self) -> int:
return self.q.popleft()
def top(self) -> int:
return self.q[0]
def empty(self) -> bool:
return len(self.q) == 0This approach takes a different perspective by nesting structures. Instead of rearranging elements, we create a new queue (or node) for each push that contains the value and a reference to the previous structure.
Each push wraps the current state inside a new container, with the new value at the front. This creates a chain where the most recent element is always immediately accessible.
In practice, this behaves like building a linked list where each node holds a value and points to the rest of the stack.
q as null (empty stack).x as the first element and the old q as the second element. Update q to point to this new structure.q to point to the second element (the rest of the stack), and return the value.q without modifying anything.true if q is null.class MyStack:
def __init__(self):
self.q = None
def push(self, x: int) -> None:
self.q = deque([x, self.q])
def pop(self) -> int:
top = self.q.popleft()
self.q = self.q.popleft()
return top
def top(self) -> int:
return self.q[0]
def empty(self) -> bool:
return not self.qWhen using one queue, after pushing a new element, the queue must be rotated exactly size - 1 times to move the new element to the front. A common mistake is rotating size times, which brings the queue back to its original state and leaves the new element at the back. The loop should run for i in range(len(q) - 1), not for i in range(len(q)).
In the two-queue approach, after moving all elements from q1 to q2 behind the new element, the queues must be swapped so that q1 always contains the elements in stack order. Forgetting to swap means subsequent pop() and top() operations will access the wrong queue, returning incorrect results or causing errors on an empty queue.