Determine Reachability in Train Schedule
Company: Glean
Role: Machine Learning Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: Solve train-schedule reachability with waiting and transfers using time-respecting graph search. The answer models earliest station arrival, preprocesses station visits, handles forward-only train routes, and explains transfer edge cases and complexity.
Constraints
- start and destination both appear somewhere in the schedule.
- Station names are arbitrary strings; the same station may appear on multiple routes and at multiple times.
- Time is discrete and equals the route index; every train starts at time 0.
- Waiting at a station for any amount of time is allowed.
- Travel on a route is forward-only: reaching a station does not let you reach earlier stations on the same route.
Examples
Input: ([["A", "B", "C"], ["D", "B", "E"]], "A", "C")
Expected Output: True
Explanation: Board train 0 at A (t=0) and ride to C (t=2).
Input: ([["A", "B", "C"], ["D", "B", "E"]], "A", "E")
Expected Output: True
Explanation: Ride train 0 to B (t=1); train 1 also visits B at t=1, so board it and ride to E (t=2).
Input: ([["A", "B", "C"], ["D", "B", "E"]], "C", "A")
Expected Output: False
Explanation: C is the last stop of train 0; travel is forward-only and no train moves C -> A.
Input: ([["A", "B", "C"], ["D", "B", "E"]], "A", "D")
Expected Output: False
Explanation: D is only the start of train 1 at t=0; nothing arrives at D after leaving A.
Input: ([["A", "B", "C", "D", "E"], ["O", "B", "G", "H", "Z"]], "A", "Z")
Expected Output: True
Explanation: Ride train 0 to B (t=1); train 1 visits B at t=1, so wait there, board it, and ride to Z (t=4).
Input: ([["X", "Y", "Z"]], "X", "X")
Expected Output: True
Explanation: start equals destination, reachable at time 0 with no travel.
Input: ([["P", "Q"], ["R", "S"]], "P", "S")
Expected Output: False
Explanation: The two routes share no station, so there is no transfer from the P/Q line to the R/S line.
Input: ([["M", "N", "O"], ["P", "Q", "O", "R"]], "M", "R")
Expected Output: True
Explanation: Ride train 0 to O at t=2; train 1 visits O at t=2 as well, so board it and ride to R (t=3).
Input: ([["M", "N", "O"], ["O", "P", "Q"], ["Q", "R"]], "M", "R")
Expected Output: False
Explanation: You arrive at O at t=2, but train 1 only visits O at t=0 (in the past), so you cannot board it; R stays unreachable.
Hints
- A plain undirected graph of stations is wrong: trains move forward in route order and time matters. Model state as (station, earliest_arrival_time).
- Because waiting is allowed, arriving earlier at a station dominates arriving later. Track the earliest time each station is reachable and only relax when you find a strictly earlier arrival.
- Preprocess each station to the list of train visits (time, route_id, index). From a reachable station at time t, you may board any visit with visit_time >= t and then ride that train to any later station on its route (arriving at that station's index time).