Implement Stack Using Queue in DSA Go - Time & Space Complexity
We want to understand how fast the stack operations run when we build a stack using a queue.
Specifically, how does the time to add or remove items change as we add more items?
Analyze the time complexity of the Push operation in this stack using one queue.
func (s *Stack) Push(x int) {
s.q.Enqueue(x)
for i := 0; i < s.q.Size()-1; i++ {
val := s.q.Dequeue()
s.q.Enqueue(val)
}
}
This code adds an item to the stack by first adding it to the queue, then moving all other items behind it.
Look at what repeats when we push an item.
- Primary operation: Loop that dequeues and enqueues all existing items in the queue.
- How many times: This loop runs once for each item already in the queue, so it runs n-1 times if there are n items.
As the number of items grows, the push operation takes longer because it moves all existing items each time.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 9 moves inside the loop |
| 100 | About 99 moves inside the loop |
| 1000 | About 999 moves inside the loop |
Pattern observation: The work grows directly with the number of items already in the stack.
Time Complexity: O(n)
This means pushing an item takes longer as the stack grows, roughly proportional to the number of items.
[X] Wrong: "Push operation is always O(1) because we just add one item."
[OK] Correct: Here, push moves all existing items to keep stack order, so it takes time proportional to the stack size.
Understanding how to build one data structure using another and analyzing its speed is a great skill that shows your problem-solving and reasoning ability.
What if we used two queues instead of one? How would the time complexity of push and pop change?
Practice
Solution
Step 1: Understand stack and queue behaviors
A stack follows Last-In-First-Out (LIFO), while a queue follows First-In-First-Out (FIFO).Step 2: Simulate stack using queue(s)
To implement a stack using queue(s), we use one or two queues to reorder elements so the last pushed element is always dequeued first.Final Answer:
Use one or two queues to simulate Last-In-First-Out (LIFO) behavior -> Option AQuick Check:
Stack = LIFO simulated by queue(s) [OK]
- Confusing stack and queue order
- Trying to sort elements instead of reordering
- Using stack to implement queue instead
Solution
Step 1: Identify queue data structure type
A queue can be implemented using a slice of integers for integer elements.Step 2: Check Go syntax for slice declaration
"var queue []int" declares a slice of integers, suitable for queue implementation.Final Answer:
var queue []int -> Option AQuick Check:
Slice of int = queue [OK]
- Using map instead of slice for queue
- Declaring wrong data type for queue
- Using string slice for integer queue
func (s *Stack) Push(x int) {
s.q = append(s.q, x)
for i := 0; i < len(s.q)-1; i++ {
s.q = append(s.q, s.q[0])
s.q = s.q[1:]
}
}
If initially s.q = [1, 2], what is s.q after calling Push(3)?Solution
Step 1: Append new element 3 to queue
Initial queue: [1, 2]. After append: [1, 2, 3].Step 2: Rotate queue elements to move 3 to front
Loop runs len(s.q)-1 = 2 times: - Iteration 1: append s.q[0]=1, queue becomes [1, 2, 3, 1], then remove first element: [2, 3, 1] - Iteration 2: append s.q[0]=2, queue becomes [2, 3, 1, 2], then remove first element: [3, 1, 2]Final Answer:
[3, 1, 2] -> Option CQuick Check:
Push moves new element front: [3,1,2] [OK]
- Not rotating queue after append
- Removing wrong elements during rotation
- Confusing order of elements after push
func (s *Stack) Pop() int {
if len(s.q) == 0 {
return -1
}
val := s.q[0]
s.q = s.q[1:]
return val
}
What is the bug in this Pop method?Solution
Step 1: Understand Pop operation in stack
Pop removes the last pushed element (top of stack).Step 2: Analyze given Pop code
Code removes s.q[0], the front of queue, which is incorrect because stack top is at front only if queue is rotated properly.Final Answer:
It removes the front element, but stack pop should remove the last pushed element -> Option DQuick Check:
Pop must remove last pushed, not front [OK]
- Removing front element without rotation
- Ignoring empty queue check
- Returning wrong default value
Solution
Step 1: Understand two-queue stack push logic
To keep stack order, new element must be at front of main queue after push.Step 2: Push by enqueue to empty q2, move all from q1 to q2, then swap
Enqueue new element to q2, move all q1 elements to q2, then swap q1 and q2 so q1 has new order with new element front.Final Answer:
Enqueue new element to q2, then dequeue all from q1 to q2, swap q1 and q2 -> Option BQuick Check:
Push uses q2 enqueue + q1 transfer + swap [OK]
- Not swapping queues after transfer
- Enqueueing new element to wrong queue
- Forgetting to move all elements
Ready to prove it?
Pass the test and this pattern moves unknown
