225. Implement Stack using Queues
On LeetCode ->Problem¶
Implement a LIFO stack using only queue operations: enqueue at back, peek/dequeue at front, size, and emptiness. Support push, pop, top, and empty using at most two queues; the follow-up allows only one.
Calls to pop and top are guaranteed valid.
Operation Return Stack (top first)
push(1) None [1]
push(2) None [2, 1]
top() 2 [2, 1]
pop() 2 [1]
empty() False [1]
class MyStack:
def __init__(self):
pass
def push(self, x: int) -> None:
pass
def pop(self) -> int:
pass
def top(self) -> int:
pass
def empty(self) -> bool:
pass
Key trick¶
After enqueueing a new value, move every older value from front to back; the newest value becomes the front.
Trap¶
- Rotate exactly the previous queue size, not the size after insertion.
- Do not use
deque.pop()or access the back: those are not permitted queue operations. - Front access through
q[0]is valid as a queue peek.
Why is it interesting?¶
It demonstrates how maintaining an invariant converts FIFO behavior into LIFO behavior, trading slower pushes for constant-time reads and removals.
Python solution¶
from collections import deque
class MyStack:
def __init__(self):
self.q = deque()
def push(self, x: int) -> None:
self.q.append(x)
# Keep the stack top at the queue front.
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 not self.q
Time: push takes \(O(n)\); pop, top, and empty take \(O(1)\).
Space: \(O(n)\) total storage, with \(O(1)\) auxiliary space per operation.
Comment on my solution¶
- Both implementations are correct and maintain the newest element at the queue front.
- Both have \(O(n)\) pushes and \(O(1)\) other operations.
- The one-queue version is preferable: it avoids allocating a replacement queue on each push.
- Replace
False if len(self.queue) else Truewithnot self.queue.
from collections import deque
# Ideas:
# a = [1]
# [1,2] [[1], 2]
#
# . -> . -> . -> .
#
# [1]
# ---
# [ ] pop 1
# [2] append 2
# [2,1] append 1 again
# ---
# [ ] pop 2, pop 1 [2, 1]
# [3] append 3
# [3, 2] append 2
# [3, 2, 1] append 1
# ------
# [1]
# ---
# [1,2] append 2
# [2,1] pop + append 1
# ---
# [2,1,3] append 3
# [1,3,2] pop + append 2
# [3,2,1] pop + append 1
# WORKS
# using 2 queues
class MyStack:
def __init__(self):
self.queue = deque()
def push(self, x: int) -> None:
q = deque([x])
for _ in range(len(self.queue)):
q.append(self.queue.popleft())
self.queue = q
def pop(self) -> int:
return self.queue.popleft()
def top(self) -> int:
return self.queue[0]
def empty(self) -> bool:
return False if len(self.queue) else True
# WORKS
# using 1 queue
class MyStack:
def __init__(self):
self.queue = deque()
def push(self, x: int) -> None:
self.queue.append(x)
for _ in range(len(self.queue) - 1):
self.queue.append(self.queue.popleft())
def pop(self) -> int:
return self.queue.popleft()
def top(self) -> int:
return self.queue[0]
def empty(self) -> bool:
return False if len(self.queue) else True