Versioned Followers and Followees
Reported by candidates from OpenAI's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
OpenAI reported this one in July 2025, and it looks friendlier than it is. Versioned Followers and Followees hands you a stream of FOLLOW, UNFOLLOW, SNAPSHOT and historical GET queries on a directed graph. The naive move is copying the whole graph at every snapshot. The problem text explicitly tells you to store change histories instead. If you're taking this OA in the next day or two, the real task is answering "who followed user X at snapshot k" fast. If you blank mid-assessment, StealthCoder can run invisibly as a safety net while you work through it.
The problem
A directed social graph has n users numbered from 0 to n - 1. A relationship u -> v means that user u follows user v. Process a finite sequence of relationship updates, immutable snapshots, and historical list queries. Every snapshot includes all earlier updates. Later updates never change an earlier snapshot. Operations FOLLOW u v activates u -> v. The relationship is inactive immediately before the command. UNFOLLOW u v deactivates u -> v. The relationship is active immediately before the command. SNAPSHOT creates the next snapshot. IDs start at 0. Append the ID as a decimal string. GET_FOLLOWERS user snapshot_id appends all users who followed user at that snapshot. GET_FOLLOWEES user snapshot_id appends all users whom user followed at that snapshot. Serialize each relationship list as a string containing ascending user IDs inside brackets, separated by commas and no spaces. Serialize an empty list as []. Only SNAPSHOT, GET_FOLLOWERS, and GET_FOLLOWEES produce output. Return those strings in command order. Historical Storage For this exercise, assume each directed relationship is stored as a change history and the whole graph is not copied for each snapshot. Use that authored history model to answer snapshot queries. Function getVersionedRelationships(n: int, operations: String[]) → String[] Examples Example 1 n = 4 operations = ["FOLLOW 0 1","FOLLOW 2 1","SNAPSHOT","GET_FOLLOWERS 1 0","GET_FOLLOWEES 0 0"] return = ["0","[0,2]","[1]"] At snapshot 0, users 0 and 2 follow user 1. User 0 follows only user 1. Example 2 n = 3 operations = ["SNAPSHOT","GET_FOLLOWERS 1 0","FOLLOW 0 1","FOLLOW 0 2","SNAPSHOT","GET_FOLLOWEES 0 0","GET_FOLLOWEES 0 1"] return = ["0","[]","1","[]","[1,2]"] Snapshot 0 is empty. The two later follows appear in snapshot 1 without changing snapshot 0. Example 3 n = 5 operations = ["FOLLOW 0 2","SNAPSHOT","FOLLOW 1 2","UNFOLLOW 0 2","FOLLOW 0 3","SNAPSHOT","GET_FOLLOWERS 2 0","GET_FOLLOWERS 2 1","GET_FOLLOWEES 0 1"] return = ["0","1","[0]","[1]","[3]"] User 0 follows 2 in snapshot 0. Before snapshot 1, user 1 follows 2, while user 0 replaces that relationship with 0 -> 3. Constraints 1 <= n <= 2000 1 <= operations.length <= 20000 0 <= u, v, user < n and u != v Every FOLLOW targets an inactive relationship. Every UNFOLLOW targets an active relationship. Every list query references a snapshot that has already been created. Commands contain single spaces between tokens. At least one command produces output.
Reported by candidates. Source: FastPrep
Pattern and pitfall
The trick is per-edge change history. For each directed pair (u,v), store a list of snapshot-indexed toggles, or keep per-user timelines of events tagged with the current snapshot count. A query at snapshot s needs the state as of s, meaning only events logged before the s+1 snapshot call. The edge case that breaks naive code is the same edge toggled several times between snapshots. Example 3 shows 0->2 removed and 0->3 added in one window. Only the final state per snapshot window matters, and an edge that flips on and off inside one window must not leak into either snapshot. Use binary search over each edge's event list, or replay events up to a cutoff index. Output must be sorted ascending, bracketed, with no spaces, and [] when empty. With n up to 2000 and 20000 operations, copying full adjacency per snapshot gets heavy. StealthCoder is the hedge if the versioning logic slips live.
If this hits your live OA and you blank, StealthCoder solves it in seconds, invisible to the proctor.
You can drill Versioned Followers and Followees 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 OpenAI's OA.
OpenAI 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.
Versioned Followers and Followees FAQ
What's the trick in Versioned Followers and Followees?+
Store a change history per relationship instead of copying the graph per snapshot. Each follow or unfollow records which snapshot window it happened in. A historical query then reconstructs state as of that snapshot by checking the last event at or before it for each candidate user.
How hard is this OpenAI OA question really?+
Medium. No exotic algorithm, but it's a design-style problem with a lot of bookkeeping. The parsing is easy. Getting the snapshot boundary right, and the output formatting exact, is where people lose points. Hand-trace Example 3 before submitting.
What edge case breaks a naive solution?+
An edge toggled multiple times between two snapshots, like unfollowing 0->2 and following 0->3 in the same window. Only the state at the moment of SNAPSHOT counts. Also watch queries against old snapshots after many later updates, which must not see those changes.
How should I format the output strings?+
Ascending user IDs in brackets, comma separated, no spaces, and [] for empty. SNAPSHOT outputs its ID as a decimal string. FOLLOW and UNFOLLOW output nothing. Results go in command order, so mixing snapshot IDs and lists in one array is expected.
How do I prepare for this in 48 hours?+
Write a small versioned-state class yourself: apply events, record snapshot counts, query by cutoff. Test with the three given examples plus a case with repeated toggles in one window. Practice sorting and joining output strings so formatting isn't your bug on the day.