Design Underground System
Problem
Implement an underground transit system that supports check-in, check-out, and average travel time queries between stations.
- 1 ≤ id ≤ 10⁶
- 1 ≤ t ≤ 10⁹
- All calls to checkIn and checkOut are consistent
- At most 10⁴ calls to each method
Example
checkIn(1, "Leyton", 3), checkIn(2, "Leyton", 8), checkOut(1, "Waterloo", 15), checkOut(2, "Waterloo", 22), getAverageTime("Leyton", "Waterloo")13.0Passenger 1 travels from Leyton to Waterloo in 12 minutes and passenger 2 travels in 14 minutes. In the route dictionary entry for ("Leyton", "Waterloo"), the total travel time becomes 26 and the trip count becomes 2. The average returned is 26 / 2 = 13.0.
Approach
Straightforward Solution
A naive approach might store all individual trip times for each route and compute averages on demand, but this would consume excessive memory and be inefficient for large numbers of trips.
Core Observation
The problem requires tracking ongoing trips and aggregating travel times for station pairs. Each passenger's check-in data must be stored until check-out, and travel times must be accumulated and counted per route to compute averages.
Path to Optimal
PreviewThe key insight is to store only the total accumulated travel time and count of trips per route, enabling O(1) average time queries. For ongoing trips, a hash map keyed by passenger id stores check-in station and time…
Full step-by-step walkthrough on Pro →
Optimal Approach
PreviewUse two hash maps: one mapping passenger ids to their check-in info (station and time), and another mapping station pairs to a tuple of (total travel time, trip count). On check-in, record the passenger's start info…
Full step-by-step walkthrough on Pro →
Want the full reasoning chain?
Unlock the complete walkthrough, line-by-line analysis, and recall drill.
Unlock ProTime
O(1) per operation
Each method uses hash map lookups and updates which have average O(1) time complexity, ensuring efficient handling of all calls.
Space
O(n)
Space scales with the number of active check-ins and unique station pairs encountered, which is at most the number of calls made.
Pattern Spotlight
Hash Maps (Stateful Aggregation)
Use hash maps to maintain dynamic state for ongoing entities and aggregate statistics keyed by composite identifiers, enabling constant-time updates and queries without storing all raw data.
Solution
| 1 | class UndergroundSystem: |
| 2 | |
| 3 | def __init__(self): |
| 4 | self.checkins = {} |
| 5 | self.routes = {} |
| 6 | |
| 7 | def checkIn(self, id: int, stationName: str, t: int) -> None: |
| 8 | self.checkins[id] = (stationName, t) |
| 9 | |
| 10 | def checkOut(self, id: int, stationName: str, t: int) -> None: |
| 11 | startStation, startTime = self.checkins.pop(id) |
| 12 | route = (startStation, stationName) |
| 13 | |
| 14 | total, count = self.routes.get(route, (0, 0)) |
| 15 | self.routes[route] = (total + (t - startTime), count + 1) |
| 16 | |
| 17 | def getAverageTime(self, startStation: str, endStation: str) -> float: |
| 18 | total, count = self.routes[(startStation, endStation)] |
| 19 | return total / count |
Step-by-Step Solution
Record Passenger Check-In Information
| 4 | self.checkins = {} |
| 5 | self.routes = {} |
| 7 | def checkIn(self, id: int, stationName: str, t: int) -> None: |
| 8 | self.checkins[id] = (stationName, t) |
Objective
To store the check-in station and time for each passenger by their unique id.
Key Insight
Tracking ongoing trips requires a fast lookup from passenger id to their check-in data. Using a hash map keyed by id allows constant-time insertion and retrieval, enabling efficient updates when the passenger checks out.
Interview Quick-Check
Core Logic
Store passenger check-in data in a hash map keyed by id to enable O(1) retrieval during check-out.
State & Boundaries
Ensure that check-in data is overwritten if a passenger checks in again before checking out, maintaining the latest state.
Common Pitfalls & Bugs
Failing to store check-in info correctly leads to incorrect trip durations or key errors during check-out.
Update Route Travel Time and Trip Count on Check-Out
To compute the trip duration for a passenger and update the aggregate travel time and count for the corresponding route.
Calculate and Return Average Travel Time for a Route
To retrieve the total travel time and trip count for a route and compute the average travel time.
2 more steps with full analysis available on Pro.
Line Analysis
This solution has 4 Critical lines interviewers watch for.
startStation, startTime = self.checkins.pop(id)
Retrieve and remove the passenger's stored check-in information.
Retrieving and removing the passenger’s check-in record ensures each trip is processed exactly once and prevents stale data from remaining in the active trip map.
self.checkins[id] = (stationName, t)
Store the passenger's starting station and timestamp.
Recording the station and time at check-in preserves the information required to compute the trip duration when the passenger checks out.
self.routes[route] = (total + (t - startTime), count + 1)
Update the route's total travel time and increment the trip count.
Updating the cumulative travel time and trip count maintains the aggregated statistics needed to compute route averages efficiently.
Full line-by-line criticality + rationale for all 9 lines available on Pro.
Test Your Understanding
Why is it necessary to store both total travel time and trip count per route instead of all individual trip times?
See the answer with Pro.
Related Problems
Hash Maps pattern
Don't just read it. Drill it.
Reconstruct Design Underground System from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.
Unlock the Design Underground System drill