Find Earliest Train Route
Company: Glean
Role: Machine Learning Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
Quick Answer: This question evaluates a candidate's ability to model and search time-dependent transit networks, combining temporal graph reasoning, state-space search, and path reconstruction for itinerary reporting.
Part 1: Earliest Arrival Time in a Train Timetable
Constraints
- 1 <= total number of stop occurrences across all trains <= 200000
- Each train itinerary has strictly increasing times
- Station names and train IDs are strings
- Times are integers in the range 0 to 10^9
- A train itinerary may contain one stop
Examples
Input: ([('T1', [('A', 0), ('B', 5)]), ('T2', [('B', 5), ('D', 8)]), ('T3', [('A', 2), ('D', 10)])], 'A', 0, 'D')
Expected Output: 8
Explanation: Take T1 from A to B, transfer immediately to T2 at time 5, and arrive at D at time 8.
Input: ([('T1', [('A', 3), ('C', 7)]), ('T2', [('A', 1), ('B', 4)])], 'A', 0, 'C')
Expected Output: 7
Explanation: The passenger can wait at A until time 3 and then take T1 directly to C.
Input: ([('T1', [('A', 0), ('B', 5)]), ('T2', [('B', 7), ('C', 9)])], 'A', 0, 'C')
Expected Output: 9
Explanation: Ride to B at time 5, wait until time 7, then take T2 to C.
Input: ([('T1', [('B', 1), ('C', 2)])], 'A', 0, 'C')
Expected Output: -1
Explanation: No train ever appears at the start station A.
Input: ([], 'A', 4, 'A')
Expected Output: 4
Explanation: Edge case: the passenger already starts at the destination.
Hints
- Think of each unique scheduled `(station, time)` as a graph node.
- Add edges for waiting to the next scheduled time at the same station, and edges for moving to the next stop on the same train.
Part 2: Reconstruct the Earliest Train Route
Constraints
- 1 <= total number of stop occurrences across all trains <= 200000
- Each train itinerary has strictly increasing times
- Station names and train IDs are strings
- Times are integers in the range 0 to 10^9
- A train itinerary may contain one stop
- If several earliest routes exist, any one is acceptable
Examples
Input: ([('T1', [('A', 0), ('B', 5), ('C', 9)])], 'A', 0, 'C')
Expected Output: {'arrival_time': 9, 'steps': [{'action': 'start', 'station': 'A', 'time': 0}, {'action': 'ride', 'train_id': 'T1', 'from_station': 'A', 'from_time': 0, 'to_station': 'C', 'to_time': 9}]}
Explanation: A single train is used for the entire journey, so the two ride segments are merged into one ride step.
Input: ([('T1', [('A', 0), ('B', 5)]), ('T2', [('B', 5), ('D', 8)])], 'A', 0, 'D')
Expected Output: {'arrival_time': 8, 'steps': [{'action': 'start', 'station': 'A', 'time': 0}, {'action': 'ride', 'train_id': 'T1', 'from_station': 'A', 'from_time': 0, 'to_station': 'B', 'to_time': 5}, {'action': 'transfer', 'station': 'B', 'time': 5, 'from_train': 'T1', 'to_train': 'T2'}, {'action': 'ride', 'train_id': 'T2', 'from_station': 'B', 'from_time': 5, 'to_station': 'D', 'to_time': 8}]}
Explanation: The transfer happens immediately at B at time 5.
Input: ([('T1', [('A', 3), ('C', 7)])], 'A', 0, 'C')
Expected Output: {'arrival_time': 7, 'steps': [{'action': 'start', 'station': 'A', 'time': 0}, {'action': 'wait', 'station': 'A', 'from_time': 0, 'to_time': 3}, {'action': 'ride', 'train_id': 'T1', 'from_station': 'A', 'from_time': 3, 'to_station': 'C', 'to_time': 7}]}
Explanation: The passenger must wait at the start station before boarding.
Input: ([('T1', [('A', 0), ('B', 5)]), ('T2', [('B', 7), ('C', 9)])], 'A', 0, 'C')
Expected Output: {'arrival_time': 9, 'steps': [{'action': 'start', 'station': 'A', 'time': 0}, {'action': 'ride', 'train_id': 'T1', 'from_station': 'A', 'from_time': 0, 'to_station': 'B', 'to_time': 5}, {'action': 'wait', 'station': 'B', 'from_time': 5, 'to_time': 7}, {'action': 'transfer', 'station': 'B', 'time': 7, 'from_train': 'T1', 'to_train': 'T2'}, {'action': 'ride', 'train_id': 'T2', 'from_station': 'B', 'from_time': 7, 'to_station': 'C', 'to_time': 9}]}
Explanation: This route includes both an intermediate wait and a transfer.
Input: ([('T1', [('B', 1), ('C', 2)])], 'A', 0, 'C')
Expected Output: None
Explanation: Edge case: no route starts from station A, so the destination is unreachable.
Hints
- Solve the earliest-arrival problem on `(station, time)` nodes, but also store a parent pointer and the edge type used to reach each node.
- After reconstructing the path, merge consecutive wait steps and same-train ride steps, then insert transfer steps whenever the train ID changes.