Formula 1 Last Lap Improvement
In a Formula 1 race, each driver completes the same number of laps. You are given a list of driver names drivers and a 2D list lapTimes, where lapTimes[i][j] represents the time in seconds that the $i^{th}$ driver took to finish the $j^{th}$ lap.
A driver's last-lap improvement is defined as the difference between their own average lap time before the last lap and their last lap time.
Specifically, for a driver:
- Calculate the average of all their laps except the last one.
- Subtract the time of the last lap from this average.
Return the name of the driver with the greatest last-lap improvement. If multiple drivers have the same improvement, return the one whose name comes first in lexicographical order.
Example 1
Input
drivers = ["Hamilton", "Verstappen"], lapTimes = [[90.5, 91.0, 88.0], [89.0, 90.5, 89.5]]Output
"Hamilton"Explanation
Hamilton's previous average: (90.5 + 91.0) / 2 = 90.75. Improvement: 90.75 - 88.0 = 2.75. Verstappen's previous average: (89.0 + 90.5) / 2 = 89.75. Improvement: 89.75 - 89.5 = 0.25. 2.75 > 0.25, so Hamilton wins.
Example 2
Input
drivers = ["Leclerc", "Russell"], lapTimes = [[95.0, 94.0, 91.0], [92.0, 93.0, 92.5]]Output
"Leclerc"
Example 3
Input
drivers = ["Alonso", "Sainz", "Norris", "Piastri"], lapTimes = [[88.5, 87.0, 89.0, 85.5], [90.0, 88.5, 87.0, 86.0], [91.0, 90.0, 89.5, 87.0], [89.0, 88.0, 90.0, 88.5]]Output
"Norris"
Constraints
2 <= lapTimes[i].length <= 10001 <= drivers.length == lapTimes.length <= 10000 <= lapTimes[i][j] <= 1000- All driver names are unique and consist of English letters.
Formula 1 Last Lap Improvement
Overview
The goal is to identify which driver improved their performance the most on the final lap compared to their average performance in all preceding laps.
For every driver, we must calculate:
- The sum of all lap times except the last one.
- The average of those times.
- The difference between that average and the last lap time.
The problem also specifies a tie-breaking rule: if multiple drivers achieve the same maximum improvement, we return the driver whose name is lexicographically first (alphabetically first).
Brute Force
The brute force approach involves iterating through the list of drivers, and for each driver, manually iterating through their lap times to calculate the sum and average. We store the improvements in a list or dictionary and then perform a second pass to find the maximum value and handle the lexicographical tie-break.
def getBestImprover(drivers: list[str], lapTimes: list[list[float]]) -> str:
improvements = []
for i in range(len(drivers)):
name = drivers[i]
times = lapTimes[i]
# Calculate average of all laps except the last one
prev_laps = times[:-1]
sum_prev = 0
for t in prev_laps:
sum_prev += t
avg_prev = sum_prev / len(prev_laps)
last_lap = times[-1]
improvement = avg_prev - last_lap
improvements.append((improvement, name))
# Find the best improvement
# We sort by improvement descending, then name ascending
# Python's sort is stable, but we can use a custom key
best_driver = None
max_imp = -float('inf')
for imp, name in improvements:
if imp > max_imp:
max_imp = imp
best_driver = name
elif imp == max_imp:
if best_driver is None or name < best_driver:
best_driver = name
return best_driver
Time complexity: O(N * M) — Where N is the number of drivers and M is the number of laps; we visit every lap time once. Space complexity: O(N) — We store the improvement value and name for each driver.
Optimal / Best Approach
The optimal approach performs the calculation in a single pass without storing all intermediate improvements. We maintain two variables: best_driver and max_improvement. As we calculate the improvement for the current driver, we compare it to our current maximum.
To handle the lexicographical requirement efficiently, we update the best_driver if:
- The current improvement is strictly greater than the
max_improvement. - The current improvement is equal to the
max_improvementAND the current name is alphabetically smaller than thebest_driver.
def getBestImprover(drivers: list[str], lapTimes: list[list[float]]) -> str:
best_driver = ""
max_improvement = -float('inf')
for i in range(len(drivers)):
name = drivers[i]
times = lapTimes[i]
# The number of laps before the last one
n_prev = len(times) - 1
# Calculate average: (Total Sum - Last Lap) / (Total Laps - 1)
# Using Python's sum() is efficient and idiomatic
avg_prev = (sum(times) - times[-1]) / n_prev
improvement = avg_prev - times[-1]
# Check if this driver is better than the current leader
if improvement > max_improvement:
max_improvement = improvement
best_driver = name
elif improvement == max_improvement:
# Tie-break: Lexicographical order
if name < best_driver:
best_driver = name
return best_driver
Time complexity: O(N * M) — We must touch every lap time at least once to calculate the average.
Space complexity: O(1) — We only store a few variables (max_improvement, best_driver) regardless of the input size, excluding the input storage itself.
Edge Cases
- Tie-breaks: The logic
name < best_drivercorrectly handles the case where two drivers have identical improvement scores (e.g., Example 4). - Negative Improvement: If a driver's last lap is slower than their average, the improvement will be negative. The initial
max_improvementis set to-float('inf')to ensure we capture even the "least bad" improvement if all drivers slowed down. - Large Lap Counts: Using
sum(times) - times[-1]is slightly more efficient than slicingtimes[:-1]as it avoids creating a new list in memory.
Fast
Comments on the solution
No comments on the solution yet. Start a thread about the editorial or your own approach.
No comments yet for Formula 1 Last Lap Improvement. Be the first to start the thread.
No submissions recorded for this problem yet. Use Submit in the editor — each judge run is stored here.
Output
Input
Expected
Your output
Run to see your output.