Bird
Raised Fist0
DSA C++programming~5 mins

Queue Using Two Stacks in DSA C++ - Time & Space Complexity

Choose your learning style10 modes available
Time Complexity: Queue Using Two Stacks
O(1) amortized
Understanding Time Complexity

We want to understand how fast operations run when we build a queue using two stacks.

Specifically, how does the time to add or remove items grow as the queue gets bigger?

Scenario Under Consideration

Analyze the time complexity of the following code snippet.


class QueueUsingStacks {
  stack<int> s1, s2;

public:
  void enqueue(int x) {
    s1.push(x);
  }

  int dequeue() {
    if (s2.empty()) {
      while (!s1.empty()) {
        s2.push(s1.top());
        s1.pop();
      }
    }
    int val = s2.top();
    s2.pop();
    return val;
  }
};
    

This code adds items to one stack and removes items from another, moving items only when needed.

Identify Repeating Operations

Identify the loops, recursion, array traversals that repeat.

  • Primary operation: Moving all items from stack s1 to s2 when s2 is empty during dequeue.
  • How many times: Each item moves at most twice: once pushed to s1, once moved to s2.
How Execution Grows With Input

Adding items (enqueue) always takes the same small time, no matter how many items.

Removing items (dequeue) sometimes takes longer when moving items, but this happens rarely.

Input Size (n)Approx. Operations
10About 10 pushes for enqueue, about 10 pops and moves for dequeue
100About 100 pushes for enqueue, about 100 pops and moves for dequeue
1000About 1000 pushes for enqueue, about 1000 pops and moves for dequeue

Pattern observation: Each item is moved only a few times, so average time per operation stays steady.

Final Time Complexity

Time Complexity: O(1) amortized

This means each add or remove operation takes about the same small time on average, even if some removals take longer.

Common Mistake

[X] Wrong: "Each dequeue always takes time proportional to the number of items because of moving stacks."

[OK] Correct: Items are moved only once per enqueue, so the costly moves are spread out, making average time per dequeue small.

Interview Connect

Understanding this helps you explain how clever data structure design can keep operations fast on average, a key skill in coding interviews.

Self-Check

"What if we moved items from s1 to s2 on every dequeue, not only when s2 is empty? How would the time complexity change?"

Practice

(1/5)
1. What is the main idea behind implementing a Queue Using Two Stacks?
easy
A. Use two stacks to store elements in sorted order
B. Use one stack for enqueue and another for dequeue to reverse order
C. Use two stacks to store elements in parallel for faster access
D. Use one stack to store elements and another to count them

Solution

  1. Step 1: Understand queue behavior

    A queue follows FIFO (First In First Out), so the first element added should be the first removed.
  2. Step 2: Use two stacks to reverse order

    One stack stores elements as they come (enqueue). The second stack reverses the order to allow dequeue in FIFO order.
  3. Final Answer:

    Use one stack for enqueue and another for dequeue to reverse order -> Option B
  4. Quick Check:

    Two stacks reverse order to simulate queue FIFO [OK]
Hint: Remember: two stacks reverse order to mimic queue [OK]
Common Mistakes:
  • Thinking both stacks store elements in the same order
  • Assuming stacks keep elements sorted
  • Using one stack only for all operations
2. Which of the following is the correct syntax to push an element x into a stack named stack1 in C++?
easy
A. stack1.push(x);
B. stack1.add(x);
C. stack1.insert(x);
D. stack1.enqueue(x);

Solution

  1. Step 1: Recall C++ stack push syntax

    The standard C++ stack uses the method push() to add elements.
  2. Step 2: Match correct method name

    Only push is the correct method; others like add, insert, or enqueue are invalid for stack.
  3. Final Answer:

    stack1.push(x); -> Option A
  4. Quick Check:

    Stack push method = push() [OK]
Hint: Stack insertion uses push() method in C++ [OK]
Common Mistakes:
  • Using enqueue() which is for queues
  • Using add() or insert() which are not stack methods
  • Confusing stack with vector methods
3. Consider the following C++ code implementing a queue using two stacks:
std::stack<int> s1, s2;

// Enqueue 1, 2, 3
s1.push(1);
s1.push(2);
s1.push(3);

// Dequeue operation
while (!s1.empty()) {
  s2.push(s1.top());
  s1.pop();
}
int front = s2.top();
s2.pop();

// What is the value of front?
medium
A. 2
B. 3
C. 1
D. Stack empty error

Solution

  1. Step 1: Trace enqueue operations

    Elements pushed into s1 in order: 1 (bottom), 2, 3 (top).
  2. Step 2: Transfer elements to s2 to reverse order

    Moving all from s1 to s2 reverses order: s2 top is 1, bottom is 3.
  3. Step 3: Identify front element

    Front of queue is s2.top() which is 1, then popped.
  4. Final Answer:

    1 -> Option C
  5. Quick Check:

    Queue front after transfer = 1 [OK]
Hint: Transfer stacks reverses order; front is bottom of first stack [OK]
Common Mistakes:
  • Assuming top of s1 is front (3 instead of 1)
  • Not reversing stack order before dequeue
  • Confusing stack top with queue front
4. The following code snippet is intended to implement dequeue operation in a queue using two stacks. Identify the error:
void dequeue() {
  if (s2.empty()) {
    while (!s1.empty()) {
      s2.push(s1.top());
      s1.pop();
    }
  }
  s1.pop();
}
medium
A. Should pop twice from s1
B. Should push elements from s2 to s1 instead
C. Missing check if both stacks are empty
D. Should pop from s2, not s1, after transfer

Solution

  1. Step 1: Understand dequeue logic

    Dequeue removes front element, which is on top of s2 after transfer.
  2. Step 2: Identify incorrect pop

    Code pops from s1 after transfer, but front is on s2, so s2.pop() is correct.
  3. Final Answer:

    Should pop from s2, not s1, after transfer -> Option D
  4. Quick Check:

    Dequeue pops from s2 top [OK]
Hint: Pop from s2 after transfer, not s1 [OK]
Common Mistakes:
  • Popping from wrong stack after transfer
  • Not checking if both stacks are empty before dequeue
  • Confusing enqueue and dequeue stacks
5. You want to implement a queue using two stacks with the following operations:

enqueue(x): Push element x to the queue.
dequeue(): Remove and return the front element.

Which approach ensures amortized O(1) time per operation?
hard
A. Push all elements to s1 on enqueue; transfer to s2 only when s2 is empty during dequeue
B. Push elements alternately to s1 and s2; pop from both stacks on dequeue
C. Transfer all elements from s1 to s2 on every enqueue operation
D. Use s1 for enqueue and s2 for dequeue but transfer elements on every dequeue regardless

Solution

  1. Step 1: Understand amortized O(1) goal

    We want to minimize costly transfers by doing them only when necessary.
  2. Step 2: Analyze each approach

    Push all elements to s1 on enqueue; transfer to s2 only when s2 is empty during dequeue transfers elements from s1 to s2 only when s2 is empty during dequeue, spreading cost over many operations.
  3. Step 3: Reject other options

    Options B, C, and D cause frequent or unnecessary transfers increasing time per operation.
  4. Final Answer:

    Push all elements to s1 on enqueue; transfer to s2 only when s2 is empty during dequeue -> Option A
  5. Quick Check:

    Transfer only when s2 empty = amortized O(1) [OK]
Hint: Transfer stacks only when dequeue stack is empty [OK]
Common Mistakes:
  • Transferring elements on every enqueue or dequeue
  • Pushing alternately causing imbalance
  • Ignoring amortized cost analysis
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard