Quick Overview

Implement queue enqueue, dequeue, and peek operations using exactly two LIFO stacks. The challenge tests transfer invariants, output ordering, amortized O(1) reasoning, large operation sequences, empty input, and compliance with restrictions against queue-like shortcuts.

Implement Queue Operations Using Two Stacks

Company: Oracle

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: hard

Interview Round: Technical Screen

# Implement Queue Operations Using Two Stacks Process a sequence of queue operations using exactly two LIFO stacks as the queue's internal data structures. Each operation is an integer list: - `[1, value]` enqueues `value`. - `[2]` dequeues and returns the oldest queued value. - `[3]` returns the oldest queued value without removing it. Return the results of all dequeue and peek operations in order. The input is guaranteed not to dequeue or peek an empty queue. Do not use a queue, deque, linked list, or array front-removal operation internally. ## Function Signature ```python def run_two_stack_queue(operations: list[list[int]]) -> list[int]: ... ``` ## Constraints - `0 <= len(operations) <= 500_000` - `-1_000_000_000 <= value <= 1_000_000_000` for every enqueue operation. - Every operation is one of the valid forms above. - Aim for `O(1)` amortized time per operation and `O(q)` space for `q` queued values. ## Example ```text Input: operations = [[1, 10], [1, 20], [3], [2], [1, 30], [2], [2]] Output: [10, 10, 20, 30] ``` ```text Input: operations = [] Output: [] ```

Overview: Implement queue enqueue, dequeue, and peek operations using exactly two LIFO stacks. The challenge tests transfer invariants, output ordering, amortized O(1) reasoning, large operation sequences, empty input, and compliance with restrictions against queue-like shortcuts.

Process a sequence of queue operations using exactly two LIFO stacks as the queue's internal data structures. Each operation is an integer list: - `[1, value]` enqueues `value`. - `[2]` dequeues and returns the oldest queued value. - `[3]` returns the oldest queued value without removing it. Return the results of all dequeue and peek operations in order, as a list. Operations that only enqueue contribute nothing to the returned list, so an input with no dequeue and no peek returns an empty list. The input is guaranteed never to dequeue or peek an empty queue. The intended approach is the classic two-stack construction: an input stack that receives every enqueue, and an output stack that serves dequeues and peeks, refilled by draining the input stack into it only when it runs empty. That gives `O(1)` amortized time per operation and `O(q)` space for `q` queued values. Do not use a queue, deque, linked list, or array front-removal operation internally. This console grades observable output only -- it cannot inspect which containers you used -- so treat the two-stack requirement as the stated expectation an interviewer would hold you to rather than as something the test suite checks. ## Function Signature ```python def run_two_stack_queue(operations: list[list[int]]) -> list[int]: ... ``` ## Example 1 ```text Input: operations = [[1, 10], [1, 20], [3], [2], [1, 30], [2], [2]] Output: [10, 10, 20, 30] ``` Enqueue 10 and 20. Peek reports 10 without removing it. Dequeue removes and returns 10. Enqueue 30. The next two dequeues return 20 and then 30. ## Example 2 ```text Input: operations = [] Output: [] ``` No operations at all, so nothing is dequeued or peeked and the result list is empty.

Constraints

  • 0 <= len(operations) <= 500_000
  • -1_000_000_000 <= value <= 1_000_000_000 for every enqueue operation
  • Every operation is exactly one of [1, value], [2], or [3]
  • The input never dequeues or peeks an empty queue
  • Aim for O(1) amortized time per operation and O(q) space for q queued values

Examples

Input: ([],)

Expected Output: []

Input: ([[1, 5]],)

Expected Output: []

Hints

  1. A single stack reverses arrival order. Ask what happens to that order if the contents are poured into a second stack.
  2. The output stack only needs refilling when it is empty; refilling it while it still holds values would interleave old and new arrivals in the wrong order.
  3. Dequeue and peek differ by exactly one step, so they can share the same preparation work.

Loading coding console...

Show the approach

Approach

The reference keeps two stacks. Every enqueue pushes onto the input stack, which therefore holds the newest values on top -- the opposite of what a dequeue needs. A dequeue or peek consults the output stack instead; when that stack is empty, the reference pops the input stack one value at a time and pushes each onto the output stack. Reversing a reversal restores arrival order, so the oldest value ends up on top of the output stack, where dequeue pops it and peek reads it without removing it. Each value is moved between the stacks at most once over its lifetime -- pushed to the input stack, transferred once, popped from the output stack -- so although one transfer can cost O(q), the cost amortizes to O(1) per operation across the whole stream. Refilling only when the output stack is empty is what makes that bound hold and is also what keeps FIFO order correct: transferring early would drop newer values underneath older ones. Results are appended in the order the dequeue and peek operations appear, and enqueue operations contribute nothing to the result list.

Time complexity:
O(n) total for n operations, i.e. O(1) amortized per operation
Space complexity:
O(q) for q values resident in the queue, plus O(r) for the r returned results