Snapshot Map with Sparse Version History
Reported by candidates from Snorkel AI's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
Snorkel AI reported this one in September 2026, and the detail that matters is the token "<NULL>" plus the rule about transient changes. It's a snapshot map with sparse version history, so the core is a hash table per key holding a list of (snapshotId, value) changes. If your OA invite lands in the next few days, expect this shape: simple operations, nasty edge cases. The trick isn't the data structure, it's knowing when NOT to record a version. StealthCoder sits invisibly on your screen as a safety net if you blank mid-assessment, but read this first and you probably won't need it.
The problem
Implement a map that supports sparse immutable snapshots. Process the operations in order: ["PUT", key, value] stores a current value. ["GET", key] emits its current value, or "<NULL>". ["DELETE", key] removes its current value. ["SNAPSHOT"] captures the current state, emits the next zero-based snapshot ID, and then advances the ID. ["GET_AT", key, snapshotId] emits the value captured for that key, or "<NULL>". PUT and DELETE emit nothing. Repeating a PUT with the same current value or deleting a missing key must not add a version. If several mutations before the next snapshot restore a key to the value from the preceding snapshot, keep no entry for that transient change. Store only per-key changes rather than copying unchanged values into every snapshot. Return all emitted strings in operation order. Function runSnapshotMap(operations: String[][]) → String[] Examples Example 1 operations = [["PUT","a","red"],["SNAPSHOT"],["PUT","a","blue"],["GET","a"],["GET_AT","a","0"],["SNAPSHOT"],["GET_AT","a","1"]] return = ["0","blue","red","1","blue"] Snapshot 0 keeps a=red. The later PUT changes only the current version and snapshot 1. Example 2 operations = [["GET","x"],["PUT","x","1"],["DELETE","x"],["SNAPSHOT"],["GET_AT","x","0"]] return = ["<NULL>","0","<NULL>"] The missing current lookup and the lookup after the delete both emit the null token. Constraints 1 <= operations.length <= 200000 Keys and values are non-empty printable ASCII strings without spaces. Values are not equal to "<NULL>". At most 1000000 distinct keys and 100000 snapshots occur. Every GET_AT snapshot ID already exists.
Reported by candidates. Source: FastPrep
Pattern and pitfall
Keep two things: a current map of key to value, and a per-key history list of (snapshotId, value) pairs, sorted by ID since snapshots only increase. Also track a dirty set of keys touched since the last snapshot. On SNAPSHOT, loop only over dirty keys, compare current value to the last recorded value in that key's history, and append only if they differ. That handles the transient rule: PUT then DELETE back to the prior state leaves no entry. Use "<NULL>" internally for deleted keys so a delete is recorded as a real change. GET_AT uses binary search for the last entry with ID <= snapshotId, returning "<NULL>" if none exists. The common pitfall is appending on every PUT, which breaks the no-duplicate rule and blows memory. Example 2 shows it: PUT then DELETE before the snapshot means x never gets an entry. With 200000 operations, per-op log time is fine. If you freeze on the dirty-set idea, StealthCoder is the hedge during the live OA.
If this hits your live OA and you blank, StealthCoder solves it in seconds, invisible to the proctor.
You can drill Snapshot Map with Sparse Version History cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Built by an Amazon engineer who would have shipped this the night before his JPMorgan OA if he'd had it.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Snorkel AI's OA.
Snorkel AI reuses patterns across OAs. Built by an Amazon engineer who would have shipped this the night before his JPMorgan OA if he'd had it. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Snapshot Map with Sparse Version History FAQ
What's the core trick in the Snorkel AI snapshot map problem?+
Record changes lazily at snapshot time, not at mutation time. Track which keys were touched since the last snapshot, then compare each one's current value to its last recorded value. Only append when they differ. That one rule covers transient changes, duplicate PUTs, and deleting missing keys.
How do I handle GET_AT efficiently?+
Store each key's history as a list of (snapshotId, value) pairs in increasing ID order. For GET_AT, binary search for the last entry with ID at or below the requested snapshot. If none exists, emit "<NULL>". That's O(log n) per query and avoids copying state into every snapshot.
How should deletes be stored?+
Treat a delete as a value change to "<NULL>" internally. At snapshot time, if the key's current state is absent and the last recorded value was something real, append a "<NULL>" entry. If the key never had a recorded value, append nothing, since absent and absent match.
What edge cases will the hidden tests hit?+
Repeated PUT with the same value, deleting a missing key, PUT then restore to the old value before a snapshot, GET_AT on a key first created after that snapshot, and snapshots with no changes at all. Each one should add no version. Test these against your own code before submitting.
How do I prepare for this in 48 hours?+
Write a version-history map from scratch twice. Practice the dirty-set snapshot step and the binary search lookup. Then run both examples by hand, especially the delete case. This is a hash table plus binary search problem, so it's manageable if you've seen the pattern once.