Design a Traffic Light System that dynamically adjusts which road gets the green light based on real-time vehicle arrivals.
The system manages a single intersection with multiple incoming roads. At any moment, at most one road can be open. An open road has a green light, and every other road is closed with a red light.
The number of roads is at most 6.
Vehicles arrive over time through calls to vehicleArrived. Each call adds new vehicles to one road.
Every road keeps track of:
1. waitingVehicles - total number of vehicles currently counted for that road,
2. redTime - how many seconds the road has been continuously closed.
The priority of a road is:
priority = waitingVehicles * 2 + redTime
As soon as vehicles start arriving then a road needs to be opened. When the system needs to choose a road to turn green, it selects the road with the highest priority. If multiple roads have the same priority, choose the lexicographically smaller road id.
When a road is selected to turn green, its green time is equal to minGreenTimeSeconds.
After minGreenTimeSeconds time has elapsed, priority is reevaluated. It may happen that the road that was previously green gets the green signal again based on current traffic.
While one road is green, every other road remains red and continues accumulating red time. When a road turns green, its redTime and waitingVehicles reset to 0. Later arrivals can increase waitingVehicles again, even while that road is currently green.
The system is time-aware. Every method that accepts currentTime uses seconds elapsed since 1 Jan 1970. Values of currentTime are guaranteed to be monotonically increasing or equal across all method calls.
Before processing any method call with currentTime, the system must first advance all green-phase transitions and reevaluations up to and including that timestamp. If a green phase ends exactly at currentTime, the reevaluation at that time happens first, the next green road is chosen starting at that same time, and then the method call is processed or answered.
Before any road has ever been opened, all roads are treated as red starting from the first method call that provides a currentTime.
This problem focuses on scheduling the traffic lights. Vehicle counts increase only through vehicleArrived, except that waitingVehicles resets to 0 whenever that road is selected to turn green.
Class
TrafficLightSystem
Exact Method Signatures
TrafficLightSystem(List<String> roadIds, int minGreenTimeSeconds)
2 ≤ roadIds.size() ≤ 6
roadIds contains unique non-empty road ids
1 ≤ minGreenTimeSeconds ≤ 300
void vehicleArrived(String roadId, int vehiclesCount, int currentTime)
roadId must already exist in the system
1 ≤ vehiclesCount ≤ 100000
0 ≤ currentTime ≤ 2147483647
- first advances the system up to and including
currentTime, including any reevaluations that happen exactly at currentTime
- then adds
vehiclesCount to the waiting vehicles of roadId at currentTime
String getCurrentGreenRoad(int currentTime)
0 ≤ currentTime ≤ 2147483647
- advances the system up to and including
currentTime
- if a reevaluation happens exactly at
currentTime, that reevaluation is processed before returning the answer
- returns the road that is green at
currentTime
String getNextGreenRoad(int currentTime)
0 ≤ currentTime ≤ 2147483647
- advances the system up to and including
currentTime
- if a reevaluation happens exactly at
currentTime, that reevaluation is processed before determining the answer
- returns the road that will become green at the next reevaluation time after
currentTime, assuming no additional vehicleArrived calls happen before that reevaluation
int getRemainingGreenTime(int currentTime)
0 ≤ currentTime ≤ 2147483647
- advances the system up to and including
currentTime
- if a reevaluation happens exactly at
currentTime, that reevaluation is processed before returning the answer
- returns how many seconds remain for the current green road at
currentTime
Rules
- At any time, at most one road can be green.
- All other roads are red while one road is green.
- The priority of a road is always
waitingVehicles * 2 + redTime.
- If two roads have the same priority, the lexicographically smaller road id is chosen first.
- When a road becomes green, both its
redTime and waitingVehicles become 0.
- While a road is red, its
redTime increases with elapsed time.
- Before processing any method call with
currentTime, the system must first advance all green-phase transitions and reevaluations up to and including that timestamp.
- If a green phase ends exactly at
currentTime, the reevaluation at that timestamp happens first, the new green road starts immediately at that same timestamp, and then the method call is processed or answered.
vehicleArrived records arrivals only after the system has already been advanced to currentTime. It does not shorten the current green phase.
- The system must lazily advance its internal state whenever a timestamped method call with
currentTime is called.
- If the current green road has already finished by
currentTime, the system must keep switching roads until it reaches the correct green road for currentTime.
- Before the first road is selected, all roads stay red starting from the first timestamped method call.
Constraints
2 ≤ number of roads ≤ 6
1 ≤ vehiclesCount ≤ 100000
0 ≤ currentTime ≤ 2147483647
currentTime values are monotonically non-decreasing across all method calls
- All road ids are unique strings
- Road ids are case-sensitive for lexicographic comparison
- You may assume every queried road id exists in the system
Examples
Example 1
TrafficLightSystem system = new TrafficLightSystem(roadIds = List.of("N", "S", "E", "W"), minGreenTimeSeconds = 10)
Output: system created
system.vehicleArrived(roadId = "N", vehiclesCount = 3, currentTime = 100)
Output: no return value
system.vehicleArrived(roadId = "E", vehiclesCount = 5, currentTime = 105)
Output: no return value
system.vehicleArrived(roadId = "S", vehiclesCount = 2, currentTime = 108)
Output: no return value
system.getCurrentGreenRoad(currentTime = 110)
Output: "E"
Explanation: The first time-aware call happened at time 100, so all roads started as red from time 100. At time 110, every road has redTime = 10. Priorities are: N = 3 * 2 + 10 = 16, S = 2 * 2 + 10 = 14, E = 5 * 2 + 10 = 20, W = 0 * 2 + 10 = 10. So E gets the green light.
system.getRemainingGreenTime(currentTime = 110)
Output: 10
Explanation: Once E becomes green at time 110, the system will reevaluate priority after minGreenTimeSeconds = 10 seconds. So the current green phase lasts until time 120.
system.getNextGreenRoad(currentTime = 110)
Output: "N"
Explanation: At time 120, priorities are reevaluated. E was green from 110 to 120, so its redTime = 0 and its waitingVehicles = 0. The other roads stayed red from time 100 to 120, so their redTime = 20. New priorities are: N = 3 * 2 + 20 = 26, S = 2 * 2 + 20 = 24, W = 0 * 2 + 20 = 20, E = 0. So N gets the next green light.
Example 2
TrafficLightSystem system = new TrafficLightSystem(roadIds = List.of("North", "South"), minGreenTimeSeconds = 10)
Output: system created
system.vehicleArrived(roadId = "North", vehiclesCount = 4, currentTime = 100)
Output: no return value
system.vehicleArrived(roadId = "South", vehiclesCount = 4, currentTime = 100)
Output: no return value
system.getCurrentGreenRoad(currentTime = 105)
Output: "North"
Explanation: At time 105, both roads have redTime = 5. Both priorities are 4 * 2 + 5 = 13. The tie is broken lexicographically, so "North" is chosen.
system.getRemainingGreenTime(currentTime = 105)
Output: 10
Explanation: The current green phase will be reevaluated after 10 seconds, at time 115.
system.getNextGreenRoad(currentTime = 105)
Output: "South"
Explanation: At time 115, North has just finished being green, so its redTime = 0 and waitingVehicles = 0. South stayed red from time 100 to 115, so its redTime = 15 and priority is 4 * 2 + 15 = 23. So South gets the next green light.
Example 3
TrafficLightSystem system = new TrafficLightSystem(roadIds = List.of("A", "B", "C"), minGreenTimeSeconds = 10)
Output: system created
system.vehicleArrived(roadId = "A", vehiclesCount = 20, currentTime = 200)
Output: no return value
system.vehicleArrived(roadId = "B", vehiclesCount = 1, currentTime = 200)
Output: no return value
system.getCurrentGreenRoad(currentTime = 205)
Output: "A"
Explanation: At time 205, all roads have redTime = 5. Priorities are: A = 20 * 2 + 5 = 45, B = 1 * 2 + 5 = 7, C = 0 * 2 + 5 = 5. So A gets the green light.
system.vehicleArrived(roadId = "A", vehiclesCount = 30, currentTime = 210)
Output: no return value
system.getNextGreenRoad(currentTime = 212)
Output: "A"
Explanation: When A turned green at time 205, its waitingVehicles reset to 0. Then 30 new vehicles arrived on A at time 210 while it was still green. The next reevaluation happens at time 215. At that time: A = 30 * 2 + 0 = 60, B = 1 * 2 + 15 = 17, C = 0 * 2 + 15 = 15. So A gets the green light again.
system.getRemainingGreenTime(currentTime = 220)
Output: 5
Explanation: A was selected again at time 215. The next reevaluation happens at time 225, so at time 220 there are 5 seconds left in the current green phase.
Example 4
TrafficLightSystem system = new TrafficLightSystem(roadIds = List.of("A", "B", "C"), minGreenTimeSeconds = 10)
Output: system created
system.vehicleArrived(roadId = "A", vehiclesCount = 4, currentTime = 300)
Output: no return value
system.vehicleArrived(roadId = "B", vehiclesCount = 3, currentTime = 300)
Output: no return value
system.vehicleArrived(roadId = "C", vehiclesCount = 1, currentTime = 300)
Output: no return value
system.getCurrentGreenRoad(currentTime = 305)
Output: "A"
Explanation: At time 305, all roads have redTime = 5. Priorities are: A = 4 * 2 + 5 = 13, B = 3 * 2 + 5 = 11, C = 1 * 2 + 5 = 7. So A gets the green light.
system.vehicleArrived(roadId = "B", vehiclesCount = 20, currentTime = 309)
Output: no return value
system.getRemainingGreenTime(currentTime = 309)
Output: 6
Explanation: The current green phase for A started at time 305 and will be reevaluated at time 315. So 6 seconds remain.
system.getNextGreenRoad(currentTime = 309)
Output: "B"
Explanation: No more vehicles arrive before the next reevaluation at time 315. At that time: A has just finished being green, so its redTime = 0 and waitingVehicles = 0. B stayed red from time 300 to 315 and now has waitingVehicles = 23, so its priority is 23 * 2 + 15 = 61. C has priority 1 * 2 + 15 = 17. So B gets the next green light.