Implement follow graph with snapshots
Company: OpenAI
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: hard
Interview Round: Technical Screen
Quick Answer: This question evaluates a candidate's ability to design efficient persistent data structures and versioned state management for time-travel queries in an in-memory directed follow graph, including handling large user IDs and operation-volume-driven space/time trade-offs.
Constraints
- 1 <= len(operations) <= 200000
- User ids a, b are integers in range [0, 10^9]
- 0 <= snapId < number of times snap() has been called
- The number of distinct (a, b) pairs touched is at most len(operations)
Examples
Input: ([('follow', 1, 2), ('snap',), ('is_following', 1, 2, 0), ('unfollow', 1, 2), ('is_following', 1, 2, 0), ('snap',), ('is_following', 1, 2, 1)],)
Expected Output: [None, 0, True, None, True, 1, False]
Explanation: After snap 0, (1->2) is True. Unfollow happens after snap 0 (in snap 1 interval), so snap 0 remains True, but snap 1 becomes False.
Input: ([('follow', 1, 2), ('unfollow', 1, 2), ('follow', 1, 2), ('snap',), ('is_following', 1, 2, 0)],)
Expected Output: [None, None, None, 0, True]
Explanation: All changes occur before the first snap; the final state before snap 0 is following.
Input: ([('unfollow', 5, 6), ('snap',), ('is_following', 5, 6, 0), ('is_following', 7, 8, 0)],)
Expected Output: [None, 0, False, False]
Explanation: Unfollowing a non-existent follow is a no-op. Unseen edges are not followed in any snapshot.
Input: ([('snap',), ('is_following', 1, 1, 0), ('follow', 1, 1), ('snap',), ('is_following', 1, 1, 0), ('is_following', 1, 1, 1)],)
Expected Output: [0, False, None, 1, False, True]
Explanation: The self-follow is created after snap 0 and is included starting at snap 1.
Input: ([],)
Expected Output: []
Explanation: No operations produce no outputs.
Input: ([('follow', 1, 2), ('follow', 1, 3), ('snap',), ('unfollow', 1, 2), ('snap',), ('is_following', 1, 2, 0), ('is_following', 1, 2, 1), ('is_following', 1, 3, 1), ('follow', 1, 2), ('is_following', 1, 2, 1), ('snap',), ('is_following', 1, 2, 2)],)
Expected Output: [None, None, 0, None, 1, True, False, True, None, False, 2, True]
Explanation: Edge (1->2) is True at snap 0, becomes False at snap 1, then is re-followed and becomes True again at snap 2. Edge (1->3) stays True.
Hints
- Store, for each directed edge (a, b), a history of (snapId, state) changes; then queries become a binary search for the latest change at or before snapId.
- If multiple updates occur for the same (a, b) within the same snapId interval, you can overwrite the last recorded value instead of appending a new one.