Implement a Snapshot Set Iterator
Company: Databricks
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: hard
Interview Round: Technical Screen
Quick Answer: This question evaluates understanding of set data structures, iterator and snapshot semantics, and the ability to reason about time and space complexity when providing stable views over mutable collections.
Constraints
- 1 <= len(operations) == len(args) <= 20000
- Values are integers in the range [-10^9, 10^9]
- Every `next(id)` refers to a previously created iterator id
- The sum of the sizes of all created snapshots does not exceed 200000
Examples
Input: (["add","add","iterator","remove","add","next","next","next","contains","contains"], [[1],[2],[],[1],[3],[0],[0],[0],[1],[3]])
Expected Output: [0, 1, 2, None, False, True]
Explanation: The iterator captures {1, 2}. After removing 1 and adding 3, that iterator still returns 1 and 2, then becomes exhausted. The live set ends as {2, 3}.
Input: (["add","add","iterator","add","iterator","remove","next","next","next","next","contains"], [[5],[1],[],[3],[],[1],[0],[1],[0],[1],[1]])
Expected Output: [0, 1, 1, 1, 5, 3, False]
Explanation: Iterator 0 snapshots {1, 5}; iterator 1 snapshots {1, 3, 5}. Removing 1 later does not change either snapshot.
Input: (["remove","iterator","next","add","add","iterator","remove","next","contains"], [[10],[],[0],[-1],[-1],[],[-1],[1],[-1]])
Expected Output: [0, None, 1, -1, False]
Explanation: Removing from an empty set does nothing. The first iterator is over an empty snapshot, so `next(0)` is `None`. Adding -1 twice keeps only one copy.
Input: (["add","add","add","iterator","remove","remove","iterator","next","next","next","next","next","next"], [[2],[-3],[0],[],[0],[2],[],[0],[1],[0],[1],[0],[0]])
Expected Output: [0, 1, -3, -3, 0, None, 2, None]
Explanation: Iterator 0 snapshots {-3, 0, 2}. After removing 0 and 2, iterator 1 snapshots only {-3}. The older iterator still returns all of its original values.
Input: (["add","add","iterator","next","remove","next","add","next","contains"], [[7],[7],[],[0],[7],[0],[8],[0],[8]])
Expected Output: [0, 7, None, None, True]
Explanation: Adding 7 twice keeps one copy. The iterator over {7} still returns 7 even after 7 is removed from the live set, and later adding 8 does not affect that iterator.
Hints
- A snapshot iterator should not point to the live set directly. Think about what data must be frozen at the moment `iterator()` is called.
- If you store each snapshot separately, each iterator only needs a cursor to know which value `next()` should return.