Find earliest time all riders become connected
Company: Uber
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: hard
Interview Round: Onsite
Quick Answer: Assesses understanding of graph connectivity, temporal event processing, and dynamic graph data-structures for determining when a set of nodes becomes a single connected component.
Part 1: Earliest Time All Riders Become Connected
Constraints
- `0 <= len(events) <= 2 * 10^5`
- Timestamps are strictly increasing integers.
- `rider_a` and `rider_b` are non-empty strings.
- `rider_a != rider_b` for every event.
- All riders that appear anywhere in the log must be considered when deciding connectivity.
Examples
Input: [(1, 'Alice', 'Bob'), (2, 'Charlie', 'Dan'), (3, 'Bob', 'Charlie'), (4, 'Alice', 'Eve'), (5, 'Bob', 'Dan')]
Expected Output: 4
Explanation: After time 3, Alice/Bob/Charlie/Dan are connected, but Eve is still separate. At time 4, Eve joins the same component, so the answer is 4.
Input: [(1, 'A', 'B'), (2, 'A', 'B'), (3, 'B', 'C')]
Expected Output: 3
Explanation: The duplicate edge at time 2 changes nothing. All three riders become connected at time 3.
Input: [(1, 'A', 'B'), (2, 'C', 'D')]
Expected Output: -1
Explanation: The riders remain split into two separate components.
Input: [(5, 'A', 'B')]
Expected Output: 5
Explanation: There are only two riders, and they become connected at the only event.
Input: []
Expected Output: -1
Explanation: No riders appear, so there is no timestamp at which connectivity is achieved.
Hints
- Model riders as nodes in an undirected graph, and process edges in time order.
- If you know the full set of riders in advance, a Disjoint Set Union (Union-Find) can track how many connected components remain.
Part 2: Earliest Time All Riders Become Connected with Shared and Blocked Events
Constraints
- `0 <= len(events) <= 2 * 10^5`
- Timestamps are strictly increasing integers.
- `action` is either `'shared'` or `'blocked'`.
- `rider_a` and `rider_b` are non-empty strings, and `rider_a != rider_b`.
- The same pair may appear many times.
- A `blocked` event for a pair that is not currently active has no effect.
- All riders that appear anywhere in the log, including riders that only appear in block events, count toward the final connectivity check.
Examples
Input: [(1, 'shared', 'Alice', 'Bob'), (2, 'shared', 'Charlie', 'Dan'), (3, 'shared', 'Bob', 'Charlie'), (4, 'blocked', 'Alice', 'Bob')]
Expected Output: 3
Explanation: At time 3, all four riders are connected. The later block at time 4 breaks one direct edge, but the earliest successful time is still 3.
Input: [(1, 'shared', 'A', 'B'), (2, 'shared', 'B', 'C'), (3, 'blocked', 'B', 'C'), (4, 'shared', 'C', 'A')]
Expected Output: 2
Explanation: All riders are already connected at time 2. Even though they disconnect later and reconnect again, the earliest valid time is 2.
Input: [(1, 'blocked', 'A', 'B'), (2, 'shared', 'A', 'B')]
Expected Output: 2
Explanation: The block at time 1 has no effect because the edge is not active yet. The shared event at time 2 connects both riders.
Input: [(1, 'shared', 'A', 'B'), (2, 'blocked', 'A', 'B'), (3, 'shared', 'C', 'D')]
Expected Output: -1
Explanation: The graph is never fully connected across all four riders.
Input: []
Expected Output: -1
Explanation: No events means there is no time at which all riders become connected.
Hints
- A normal Union-Find handles edge additions well, but not deletions. Try processing the problem offline instead of updating one mutable graph directly.
- Think about the time interval during which each edge is active, then add that edge to a segment tree over time and use a rollback DSU while traversing it.