Katkat

Implement a Removable Nested-List Iterator

AirbnbSoftware Engineer · Technical Screen

Last updated

Design and implement a nested-list iterator supporting `hasNext`, `next`, and an in-place `remove` operation that alters the original data structure.

Problem Statement

Implement an iterator class, NestedIterator, that traverses an arbitrarily nested list of integers (where each element can either be an integer or another list of integers) and supports in-place deletion.

The iterator must implement the following methods:

  • __init__(nested_list: list): Initializes the iterator with the reference to the original nested list.
  • next() -> int: Returns the next integer in the depth-first traversal and advances the pointer. Raises RuntimeError if there are no more integers.
  • hasNext() -> bool: Returns True if there are still integers remaining to visit, or False otherwise. Multiple consecutive calls to hasNext() must be idempotent and must not skip any elements.
  • remove() -> None: Deletes the integer returned by the most recent call to next() directly from the underlying nested list. Calling remove() before next() has been called, or calling remove() twice without an intervening next() call, must raise RuntimeError.

Any deletions must be reflected in the original nested_list passed into the constructor.

Interface

class NestedIterator:
    def __init__(self, nested_list: list):
        pass

    def next(self) -> int:
        pass

    def hasNext(self) -> bool:
        pass

    def remove(self) -> None:
        pass

Examples

Example 1

data = [[1, 2], [], [3]]
it = NestedIterator(data)

assert it.hasNext() == True
assert it.next() == 1
it.remove()               # Removes 1 from data
assert it.next() == 2
assert it.next() == 3
assert it.hasNext() == False

# The original structure reflects the removal:
assert data == [[2], [], [3]]

Example 2

data = [1, [[]], [2, 3]]
it = NestedIterator(data)

assert it.next() == 1
assert it.next() == 2
it.remove()               # Removes 2
# it.remove()             # Would raise RuntimeError if called again immediately
assert it.next() == 3
assert data == [1, [[]], [3]]

Constraints

  • Total number of integers and sublists across all levels is at most 10^5.
  • Integer values are in the range [-10^9, 10^9].
  • The maximum depth of nesting is at most 10^3.
  • Auxiliary space complexity (excluding the input itself) should be O(D), where D is the maximum depth of nesting.

Edge Cases to Consider

  • Consecutive empty lists at any depth (e.g., [[], [[]], 1]).
  • Calling hasNext() multiple times in a row before calling next().
  • Calling remove() at the beginning before any next() call.
  • Calling remove() on the last element in a sublist or the overall list.

Hints

Hint 1

Maintain a stack of references `(current_list, current_index)` to track your traversal path without copying the data.

Hint 2

Make `hasNext()` prepare the next valid integer by advancing past empty lists and descending into nested sublists as needed.

Hint 3

When `remove()` deletes an item at `index`, decrement that level's index pointer by 1 so the next forward step does not skip the adjacent element.

Follow-up questions

  • How would you support a `peek()` operation without altering the legal calling sequence for `remove()`?
  • If an entire sublist becomes empty as a result of deletions, should it be removed from its parent? How would you implement that cascade?
  • How would you make this iterator thread-safe if another thread could concurrently read or write to `nested_list`?