There are n cars traveling to the same destination on a one-lane highway.
You are given two arrays of integers position and speed, both of length n.
position[i] is the position of the ith car (in miles)speed[i] is the speed of the ith car (in miles per hour)The destination is at position target miles.
A car can not pass another car ahead of it. It can only catch up to another car and then drive at the same speed as the car ahead of it.
A car fleet is a non-empty set of cars driving at the same position and same speed. A single car is also considered a car fleet.
If a car catches up to a car fleet the moment the fleet reaches the destination, then the car is considered to be part of the fleet.
Return the number of different car fleets that will arrive at the destination.
Example 1:
Input: target = 10, position = [1,4], speed = [3,2]
Output: 1Explanation: The cars starting at 1 (speed 3) and 4 (speed 2) become a fleet, meeting each other at 10, the destination.
Example 2:
Input: target = 10, position = [4,1,0,7], speed = [2,2,1,1]
Output: 3Explanation: The cars starting at 4 and 7 become a fleet at position 10. The cars starting at 1 and 0 never catch up to the car ahead of them. Thus, there are 3 car fleets that will arrive at the destination.
Constraints:
n == position.length == speed.length.1 <= n <= 10000 < target <= 10000 < speed[i] <= 1000 <= position[i] < targetposition are unique.
You should aim for a solution with O(nlogn) time and O(n) space, where n is the size of the input array.
First draw a picture of all the points which represents the positions and respective speeds of the cars. It is appropriate to represent the position and speed of each car as an array, where each cell corresponds to a car. It is also logical to sort this array based on the positions in descending order. Why?
Because a car can only form a fleet with another car that is ahead of it, sorting the array in descending order ensures clarity about the final speed of each car. Sorting in ascending order would create ambiguity, as the next car might form a fleet with another car while reaching the target, making it difficult to determine its final speed.
Calculating the time for a car to reach the target is straightforward and can be done using the formula: time = (target - position) / speed. Now, it becomes easy to identify that two cars will form a fleet if and only if the car ahead has a time that is greater than or equal to the time of the car behind it. How can we maintain the total number of fleets happened while going through the array? Maybe a data structure is helpful.
We can use a stack to maintain the times of the fleets. As we iterate through the array (sorted in descending order of positions), we compute the time for each car to reach the target and check if it can form a fleet with the car ahead. If the current car's time is less than or equal to the top of the stack, it joins the same fleet. Otherwise, it forms a new fleet, and we push its time onto the stack. The length of the stack at the end represents the total number of fleets formed.
Before attempting this problem, you should be comfortable with:
Cars that start closer to the target are processed first.
For each car, we compute the time it will take to reach the target.
If a car behind reaches the target no faster than the car in front, it will eventually catch up and join the same fleet.
So we only keep the car’s time if it forms a new fleet; otherwise, it merges with the previous one.
Using a stack helps us easily compare each car’s time with the fleet ahead of it.
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: # Reverse Sorted Order
stack.append((target - p) / s)
if len(stack) >= 2 and stack[-1] <= stack[-2]:
stack.pop()
return len(stack)After sorting cars from closest to the target to farthest, we calculate how long each one needs to reach the target.
A car forms a new fleet only if it takes longer than the fleet in front of it.
If it takes the same time or less, it will eventually catch up and merge into that fleet.
So instead of using a stack, we just keep track of the most recent fleet time.
prevTime) - the time of the car closest to the target.prevTime, it cannot catch up and forms a new fleet.prevTime to this new time.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)):
currCar = pair[i]
currTime = (target - currCar[0]) / currCar[1]
if currTime > prevTime:
fleets += 1
prevTime = currTime
return fleetsSorting cars by position in ascending order (farthest from target first) instead of descending order causes incorrect fleet merging. Cars must be processed from closest to the target first, since a car behind can only merge with the fleet ahead of it.
# Wrong: ascending order
pair.sort()
# Correct: descending order (closest to target first)
pair.sort(reverse=True)Using < instead of <= when comparing arrival times misses the case where two cars arrive at exactly the same time. If a car behind arrives at the same time or earlier than the car ahead, it joins that fleet.
# Wrong: misses equal arrival times
if stack[-1] < stack[-2]:
# Correct: cars arriving at same time merge
if stack[-1] <= stack[-2]:In languages like Java or C++, dividing two integers results in integer division, which truncates the decimal part. Since arrival times are often fractional, this leads to incorrect comparisons and wrong fleet counts.
// Wrong: integer division truncates
int time = (target - position) / speed;
// Correct: cast to double for precise time
double time = (double)(target - position) / speed;