Problem Overview
We are given n cars traveling toward the same destination on a one-lane highway.
Each car has:
- a starting
position - a
speed - the same destination at
target
A key rule is that cars cannot pass each other. If a faster car catches up to a slower car ahead of it, it becomes part of the same fleet and continues at the slower car’s speed.
We need to return the number of car fleets that eventually reach the destination.
Key Idea
Instead of simulating the movement of every car, we calculate how long each car would take to reach the destination.
For a car at position p with speed s:
time = (target - p) / sNow, the important part is the order.
We sort cars by position in descending order, meaning we process the cars closest to the destination first.
Why?
Because a car behind can only catch up to cars ahead of it. So we compare each car’s arrival time with the fleet ahead.
Stack-Based Solution
from typing import List
class Solution:
def carFleet(self, target: int, position: List[int], speed: List[int]) -> int:
pair = [(p, s) for p, s in zip(position, speed)]
pair.sort(reverse=True)
stack = []
for p, s in pair:
stack.append((target - p) / s)
if len(stack) >= 2 and stack[-1] <= stack[-2]:
stack.pop()
return len(stack)Explanation
First, we combine each car’s position and speed into a pair:
pair = [(p, s) for p, s in zip(position, speed)]Then we sort the cars from closest to the destination to farthest:
pair.sort(reverse=True)For each car, we calculate its time to reach the destination and push it onto the stack.
If the current car takes less time than or equal to the fleet ahead, that means it will catch up before or exactly at the destination.
So it becomes part of the fleet ahead, and we remove it from the stack:
if len(stack) >= 2 and stack[-1] <= stack[-2]:
stack.pop()At the end, the number of items left in the stack is the number of fleets.
Optimized Variable-Based Solution
We can solve the same problem without using a stack.
from typing import List
class Solution:
def carFleet(self, target: int, position: List[int], speed: List[int]) -> int:
pair = [(p, s) for p, s in zip(position, speed)]
pair.sort(reverse=True)
fleets = 1
prevTime = (target - pair[0][0]) / pair[0][1]
for i in range(1, len(pair)):
currTime = (target - pair[i][0]) / pair[i][1]
if currTime > prevTime:
fleets += 1
prevTime = currTime
return fleetsExplanation
The first car closest to the destination always forms at least one fleet.
So we start with:
fleets = 1We store its arrival time as prevTime.
Then, for every car behind it, we calculate currTime.
If:
currTime <= prevTimethen the current car catches up to the fleet ahead, so it does not create a new fleet.
But if:
currTime > prevTimethen the current car is too slow to catch up, so it forms a new fleet.
In that case, we increase the fleet count and update prevTime.
Why Sorting Matters
Sorting by position in descending order lets us process cars from front to back.
This is important because only cars behind can merge into cars ahead. A car in front never needs to care about a car behind unless that car catches up.
By moving from closest to farthest, we only need to track the slowest reachable fleet time ahead.
Complexity Analysis
Let n be the number of cars.
Sorting takes:
O(n log n)Looping through the cars takes:
O(n)So the total time complexity is:
O(n log n)The stack solution uses:
O(n)extra space.
The variable-based solution uses:
O(1)extra space, not counting the sorted pair list.
Final Thoughts
The main trick in this problem is realizing that we do not need to simulate the cars moving.
We only need to calculate each car’s arrival time and process the cars from closest to farthest from the destination.
If a car behind arrives sooner than or at the same time as the fleet ahead, it merges into that fleet. Otherwise, it becomes a new fleet.
This makes the problem much simpler and gives us an efficient solution.