Skip to main content

Implement Stack using Queues

LeetCode 225 | Difficulty: Easy​

Easy

Problem Description​

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:

- You must use **only** standard operations of a queue, which means that only `push to back`, `peek/pop from front`, `size` and `is empty` operations are valid.

- Depending on your language, the queue may not be supported natively. You may simulate a queue using a list or deque (double-ended queue) as long as you use only a queue's standard operations.

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 <= 9`

- At most `100` calls will be made to `push`, `pop`, `top`, and `empty`.

- All the calls to `pop` and `top` are valid.

Follow-up: Can you implement the stack using only one queue?

Topics: Stack, Design, Queue


Approach​

Stack​

Use a stack (LIFO) to track elements that need future processing. Process elements when a "trigger" condition is met (e.g., finding a smaller/larger element). Monotonic stack maintains elements in sorted order for next greater/smaller element problems.

When to use

Matching brackets, next greater element, evaluating expressions, backtracking history.

Design​

Choose the right data structures to meet the required time complexities for each operation. Consider hash maps for O(1) access, doubly-linked lists for O(1) insertion/deletion, and combining structures for complex requirements.

When to use

Implementing a data structure or system with specific operation time requirements.


Solutions​

Solution 1: C# (Best: 124 ms)​

MetricValue
Runtime124 ms
Memory23.4 MB
Date2019-12-31
Solution
public class MyStack {

private Queue<int> q;

/** Initialize your data structure here. */
public MyStack()
{
q = new Queue<int>();
}

/** Push element x onto stack. */
public void Push(int x)
{
q.Enqueue(x);
for (int i = 1; i < q.Count; i++)
{
q.Enqueue(q.Dequeue());
}
}

/** Removes the element on top of the stack and returns that element. */
public int Pop()
{
return q.Dequeue();
}

/** Get the top element. */
public int Top()
{
return q.Peek();
}

/** Returns whether the stack is empty. */
public bool Empty()
{
return q.Count == 0;
}
}

/**
* Your MyStack object will be instantiated and called as such:
* MyStack obj = new MyStack();
* obj.Push(x);
* int param_2 = obj.Pop();
* int param_3 = obj.Top();
* bool param_4 = obj.Empty();
*/

Complexity Analysis​

ApproachTimeSpace
Stack$O(n)$$O(n)$

Interview Tips​

Key Points
  • Start by clarifying edge cases: empty input, single element, all duplicates.
  • Think about what triggers a pop: is it finding a match, or finding a smaller/larger element?
  • Clarify the expected time complexity for each operation before choosing data structures.