interviewpath
  • 0day streak
  • 10total XP
  • Level 1
0/6

Unit 1 · Algorithms · Lesson 5 of 24

Stacks, queues and deques

Stacks, queues and deques are the simplest structures with a rule about which element leaves next. Recognizing last-in-first-out structure (nesting, undo, expression evaluation) and first-in-first-out structure (levels, buffering, time windows) turns many problems into short linear-time code.
About 3 h 30 minFocus mode

Step 1: Learn the ideas

  • Stack (LIFO) and queue (FIFO) interfaces
  • Balanced delimiters and nested structure
  • Expression evaluation: postfix, precedence and parentheses
  • Augmented stacks (min stack)
  • Queue from two stacks and amortized analysis
  • Ring buffers: modular indices, full versus empty
  • Deques and their library implementations
  • Explicit stacks in place of recursion
  • Queues for BFS and time-window buffering

Why it matters

Many problems hide a rule about which item to handle next. If the most recently opened thing must be closed first (brackets, function calls, undo history, nested encodings), the structure is a stack. If things must be handled in arrival order (BFS levels, request buffers, events inside a time window), it is a queue. A deque supports both ends and underlies the monotonic-deque technique. In systems the same structures appear as call stacks, ring buffers in drivers and logging pipelines, and work queues.

Core ideas

Pattern: Stack. Push when something opens, pop when it closes, and check that what you pop matches. For Valid Parentheses the invariant is "the stack holds exactly the unmatched openers, innermost on top"; the string is valid when every closer matches the top and the stack ends empty. The same shape handles postfix evaluation (push operands; on an operator pop two, minding operand order for subtraction and division), Decode String (push the current context when entering brackets, pop and combine when leaving) and simulations such as Asteroid Collision. In all of them each element is pushed and popped at most once, so a while loop inside the for loop still gives O(n) total.

Augmented stacks. Store extra state with each entry. A min stack pushes (value, min_so_far): the minimum of a stack changes only on push or pop, so the top entry always knows it.

Queues and amortization. A queue built from two stacks pushes onto inbox and pops from outbox, refilling outbox from inbox only when outbox is empty. One pop can cost O(n), but each element moves from inbox to outbox at most once, so any n operations cost O(n): amortized O(1) per operation. Be able to state this argument in two sentences.

Ring buffers. A fixed array with a head index and a count implements a bounded queue or deque: enqueue at (head + count) % cap, dequeue at head and advance it modulo cap; a front insertion moves head back by one modulo cap. Keeping count (or leaving one slot unused) removes the classic ambiguity where head == tail could mean either full or empty.

Deques. O(1) push and pop at both ends. Use them for BFS queues, for windows that evict old items, and as the basis of the monotonic-deque pattern. Python has collections.deque, Java ArrayDeque, C++ std::deque; in JavaScript use an array with a head index or write a small ring buffer.

Explicit stacks for recursion. Any recursive DFS can be written with a stack of pending work. This avoids recursion limits (CPython's default is typically 1000 frames) and makes the order explicit. Push children in reverse order to match the recursive pre-order; for post-order, push a node twice with a flag that says whether its children are done.

Common misconceptions

  • "A dynamic array works as a queue." Removing from the front shifts every remaining element (Python list.pop(0); JavaScript shift() is specified the same way), which can make a BFS quadratic.
  • "A queue from two stacks is O(n) per operation." A single operation can be O(n), but the amortized cost is O(1) because each element moves once.
  • "head == tail means empty." Without a count or a spare slot it can also mean full; choose one convention and test both states and wrap-around.
  • "A loop inside a loop over a stack is quadratic." If every element is pushed and popped at most once, the total work is linear.
  • "An iterative DFS visits nodes in the same order as the recursive one." Only if you push children in reverse order.

How to approach it

When you see nesting, matching or "most recent", reach for a stack and say what it holds. When you see levels, arrival order or a time window, reach for a queue or deque. Count pushes and pops to argue linear time. Interviewers typically extend these problems: add a getMin, bound the capacity, support both ends, or make the queue safe for concurrent producers and consumers, a natural follow-up for backend and systems roles.

Suggested order

  1. 1Read MIT 6.006 Lecture 2 (Data Structures) for sequence operations at either end and the amortized growth of array-backed stacks.
  2. 2Read the note on using lists as queues in the Python tutorial, then find the equivalent deque type and its costs in your own language.
  3. 3Solve Valid Parentheses and Evaluate Reverse Polish Notation, stating the stack invariant before coding.
  4. 4Solve Min Stack and Implement Queue using Stacks, writing the amortized argument for the latter in two sentences.
  5. 5Solve Number of Recent Calls with a queue, then Design Circular Queue with an explicit full and empty convention.
  6. 6Solve Decode String and Asteroid Collision, then Design Circular Deque.
  7. 7Solve Basic Calculator as the harder review problem, saving context on a stack at each parenthesis.

Step 2: Check off what you can do

Tap each one you can genuinely do or explain. Each earns 10 XP.

Step 3: Go deeper

  • MIT 6.006 Introduction to Algorithms (Spring 2020)Start here

    MIT OpenCourseWare

    Section: Lecture 2: Data Structures

    The sequence interface, operations at the first and last positions, and amortized dynamic-array growth behind array-backed stacks.

    Open(opens in a new tab)Link responded, 5 Oct 2026
  • Python documentation: costs of built-in types and the container modules

    Python Software Foundation (docs.python.org)

    Section: Tutorial 5.1.2: Using Lists as Queues

    The documented reason lists are poor queues and the deque alternative; check the equivalent guidance for your language.

    Open(opens in a new tab)Link responded, 5 Oct 2026
  • cppreference: C++ containers library, priority_queue, sort and lower_bound

    cppreference.com

    Section: std::deque

    Constant-time operations at both ends, and which deque operations invalidate iterators versus references.

    Open(opens in a new tab)Link responded, 5 Oct 2026
  • Java SE 25 API documentation: java.util collections

    Oracle

    Section: ArrayDeque

    Why ArrayDeque is the documented choice for both stacks and queues in Java, and which of its operations are linear.

    Open(opens in a new tab)Link responded, 5 Oct 2026

Step 4: Practice

For each problem, say what the stack or queue holds and when an element leaves it, then count pushes and pops to justify linear time. Test the design problems (Design Circular Queue, Design Circular Deque) explicitly in the empty, full and wrapped-around states. Basic Calculator is the harder review problem: a stack of saved contexts plus careful sign handling.

Record attempts on each problem’s page (+15 XP, +10 more when solved on your own).

Step 5: Test yourself

Answer each one out loud or on paper before you finish the lesson.

  1. Question 1What does the stack contain at each step of Valid Parentheses?
  2. Question 2Why is a queue from two stacks amortized O(1) even though one pop can move n elements?
  3. Question 3How do you tell full from empty in a ring buffer?
  4. Question 4Which type do you use for a FIFO queue in your interview language, and what does removing from the front cost?
  5. Question 5How do you obtain pre-order versus post-order with an explicit stack?

You’re done when you can

  • Solve two unseen stack problems in under 20 minutes each, stating the invariant before coding.
  • Explain the amortized cost of a queue built from two stacks without notes.
  • Implement a ring-buffer deque that passes empty, full and wrap-around tests on the first run.
  • Rewrite a recursive tree traversal iteratively with an explicit stack, in pre-order and post-order.

Finish the lesson

How confident do you feel?

Lesson complete!

+50 XP

Reviews will come up on the Practice tab so it sticks.

Unlocks next: Monotonic stacks and deques, Recursion and backtracking, Graph traversal: BFS, DFS and components

Your notes and study time

Log study time