Let's design an underground railway system to track customer travel times between stations. We want to calculate the average travel time between any two given stations.
Implement the UndergroundSystem
class with the following methods:
void checkIn(int id, string stationName, int t)
: A customer with card ID id
checks in at stationName
at time t
. A customer can only be checked into one place at a time.
void checkOut(int id, string stationName, int t)
: A customer with card ID id
checks out from stationName
at time t
.
double getAverageTime(string startStation, string endStation)
: Returns the average time it takes to travel from startStation
to endStation
. This is computed from all previous trips directly from startStation
to endStation
. Assume at least one customer has traveled from startStation
to endStation
before this method is called, and travel time may differ in each direction.
Example:
UndergroundSystem undergroundSystem = new UndergroundSystem();
undergroundSystem.checkIn(45, "Leyton", 3);
undergroundSystem.checkIn(32, "Paradise", 8);
undergroundSystem.checkIn(27, "Leyton", 10);
undergroundSystem.checkOut(45, "Waterloo", 15); // Customer 45: Leyton -> Waterloo in 12
undergroundSystem.checkOut(27, "Waterloo", 20); // Customer 27: Leyton -> Waterloo in 10
undergroundSystem.checkOut(32, "Cambridge", 22); // Customer 32: Paradise -> Cambridge in 14
undergroundSystem.getAverageTime("Paradise", "Cambridge"); // Returns 14.0
undergroundSystem.getAverageTime("Leyton", "Waterloo"); // Returns 11.0
undergroundSystem.checkIn(10, "Leyton", 24);
undergroundSystem.getAverageTime("Leyton", "Waterloo"); // Returns 11.0
undergroundSystem.checkOut(10, "Waterloo", 38); // Customer 10: Leyton -> Waterloo in 14
undergroundSystem.getAverageTime("Leyton", "Waterloo"); // Returns 12.0
How would you implement this system to efficiently compute average travel times?
A naive approach would be to store all travel times for each route in a list. When getAverageTime
is called, we would simply calculate the average of the travel times in the list. This is straightforward but can be inefficient if there are many trips.
class UndergroundSystem:
def __init__(self):
self.check_in_data = {}
self.route_times = {}
def checkIn(self, id: int, stationName: str, t: int) -> None:
self.check_in_data[id] = (stationName, t)
def checkOut(self, id: int, stationName: str, t: int) -> None:
start_station, start_time = self.check_in_data[id]
del self.check_in_data[id]
route = (start_station, stationName)
travel_time = t - start_time
if route not in self.route_times:
self.route_times[route] = []
self.route_times[route].append(travel_time)
def getAverageTime(self, startStation: str, endStation: str) -> float:
route = (startStation, endStation)
times = self.route_times[route]
return sum(times) / len(times)
checkIn
: O(1)checkOut
: O(1)getAverageTime
: O(N), where N is the number of trips between the two stations.To improve efficiency, we can maintain running sums and counts of travel times for each route. This avoids iterating through a potentially large list every time getAverageTime
is called.
class UndergroundSystem:
def __init__(self):
self.check_in_data = {}
self.route_data = {}
def checkIn(self, id: int, stationName: str, t: int) -> None:
self.check_in_data[id] = (stationName, t)
def checkOut(self, id: int, stationName: str, t: int) -> None:
start_station, start_time = self.check_in_data[id]
del self.check_in_data[id]
end_station = stationName
travel_time = t - start_time
route = (start_station, end_station)
if route not in self.route_data:
self.route_data[route] = [0, 0]
self.route_data[route][0] += travel_time
self.route_data[route][1] += 1
def getAverageTime(self, startStation: str, endStation: str) -> float:
route = (startStation, endStation)
total_time, count = self.route_data[route]
return total_time / count
checkIn
: O(1)checkOut
: O(1)getAverageTime
: O(1)getAverageTime
is called. Thus, we do not need to handle this edge case explicitly.