</> MAANG.io
coding interview ยท 101

Foundations

Master coding interviews with comprehensive coverage of data structures, algorithms, and problem-solving techniques. Progress from fundamentals to advanced topics with expertly curated content.

0/255 solved 0% complete

Iterators

What is this?

An iterator is a little device that hands you the next item in a sequence each time you ask, without ever laying out the whole sequence at once. Picture a Pez dispenser: it gives you one candy per click and keeps the rest tucked away. The design trick is to hold just enough state โ€” a pointer or two, a small stack โ€” so you can always produce the next item on demand and know when you've run out.

flowchart TD A["Caller asks for the next element"] --> B["hasNext checks if a valid element exists"] B --> C["next returns the current element"] C --> D["A helper advances the cursor to the next valid spot"] D --> A

๐Ÿ’ก Fun fact: This lazy, one-at-a-time style is how huge data pipelines stay fast โ€” tools like Python generators and database cursors stream billions of rows without ever loading them all into memory, producing each row only at the moment you ask for it.

๐Ÿ”“ The 3 problems in this chapter are free. Sign in with Google or Microsoft to start solving.


Core idea: An iterator exposes a sequence one element at a time via next() / hasNext() โ€” without ever building the whole sequence in memory. The design challenge is holding just enough state (a stack, a pair of pointers, a run index) to produce the next element on demand, and maintaining one clear invariant between calls.


Lazy beats eager

The naive move is to flatten everything up front in the constructor, then index it โ€” but that defeats the purpose: O(total) memory, and pointless if the caller stops early. A real iterator keeps a small cursor and computes the next element only when asked:

Eager builds all elements for O(total) space with work done whether or not it's used; lazy holds a tiny cursor for O(state) space with work spread across next() calls

The recurring trick is an invariant maintained by a helper: after construction and after every next(), the cursor sits on a valid element (or past the end). One _advance()/_push_left() routine enforces it; everything else falls out.


The three problems

Iterators (lazy cursors) branch into BST Iterator (stack = un-yielded left spine), RLE Iterator (walk runs, don't decompress) and Flatten 2D Vector (two pointers, skip empties)

Problem State held Invariant
Binary Search Tree Iterator a stack of un-yielded ancestors the stack top is the next-smallest; O(h) space, amortized O(1) next
RLE Iterator index into the runs + remaining count consume from runs lazily; never expand the decoded sequence
Flatten 2D Vector (outer, inner) pointers + _advance() the cursor always rests on a real element or off the end (skip empty inner lists)

Each one is a different shape of "produce the next element with bounded state": a tree (defer the right subtree via a stack), compressed data (walk runs without decompressing), and a jagged collection (two pointers that skip gaps).


The pattern

Decide the minimal state that lets you produce the next element, then write one helper that re-establishes the "cursor is valid" invariant after each call. hasNext() is "is the cursor valid?"; next() returns the current element and advances. Each element is touched O(1) amortized โ€” the deferred work (pushing a left spine, skipping empties) averages out.


๐Ÿ““ Draw it yourself

  1. The breathing stack. For the BST iterator, draw the stack holding the leftmost-spine; pop on next(), then push the left spine of the popped node's right child.
  2. Skip the empties. For Flatten 2D Vector, draw rows with some empty inner lists and an _advance() that hops the cursor over them to the next real element.

Snap photos and embed them with the /host-diagrams skill.


Key takeaways

  • Lazy, not eager: hold a small cursor; never pre-materialize the whole sequence.
  • One invariant, one helper: "the cursor is on a valid next element," re-established by _advance()/stack-push after each call.
  • Amortized O(1): deferred work (left-spine pushes, empty-list skips) averages to constant per next(); space is O(state), not O(n).
  • Same idea, three shapes: tree (stack), compressed runs (run index), jagged 2-D (two pointers).
  • Why interviewers like it: iterators test whether you reason about state between calls and laziness โ€” the core of streaming and cursor APIs.

Order: Binary Search Tree Iterator โ†’ RLE Iterator โ†’ Flatten 2D Vector.

RLE Iterator

Core idea: The input is already compressed as (count, value) runs โ€” so to consume n items you subtract from the current run's count and skip whole runs you exhaust, never expanding the runs into the giant sequence they describe.


Problem, rephrased

You're streaming a paint-by-numbers instruction tape for a plotter. Instead of listing every cell's color, the tape is compressed as alternating (count, color) pairs:

tape = [3, 8, 0, 9, 2, 5] grouped into run0 (3, 8), run1 (0, 9) and run2 (2, 5)

Read it as "three 8s, zero 9s, two 5s", which describes the decoded sequence:

8  8  8  5  5

You build the iterator once with that tape, then call next(n):

  • next(n) consumes the next n cells of the decoded sequence and returns the color of the last cell consumed.
  • If fewer than n cells remain, it consumes whatever is left and returns -1 (we ran off the end).
  • Consecutive calls continue where the last one stopped โ€” the cursor is sticky.

Operations / expected

Starting from tape = [3, 8, 0, 9, 2, 5] โ†’ decodes to [8, 8, 8, 5, 5]:

Call Cells consumed (this call) Remaining after Returns Why
next(2) 8 8 8 5 5 8 last of the two consumed is an 8
next(1) 8 5 5 8 finishes off the run of 8s
next(1) 5 5 5 crossed into the run of 5s
next(2) 5 then nothing โ€” (empty) -1 only 1 left, needed 2 โ†’ exhausted

The headline catch: a single count can be up to a billion. You must answer all of this without ever materializing [8, 8, 8, 5, 5, โ€ฆ].


Sign in to continue reading

The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.

Sign in to read the full lesson

Sign in to MAANG.io

Use your Google or Microsoft account โ€” no password to remember.

Continue with Google Continue with Microsoft

Please accept the terms above to continue.