You are given a target position target
on a straight road and two integer arrays position
and speed
, both of length n
, where position[i]
is the starting position of the i
-th car, and speed[i]
is its speed (in the same units as the target).
All cars are driving towards the target in the same direction. A car cannot pass another car ahead of it, but it can catch up and form a fleet with cars in front of it. When a car catches up to another car or fleet, it joins that fleet and they travel together at the same speed (the slowest speed in the fleet).
A car fleet is a group of cars that arrive at the destination at the same time.
Your task is to compute how many car fleets will arrive at the target. Each car belongs to exactly one fleet, and a fleet may consist of just one car.
Constraints:
0 < position.length == speed.length <= 10^4
0 < position[i] < target <= 10^6
At first glance, you might try to simulate each car's journey step by step, tracking their positions as they move and merge. However, this would be inefficient and unnecessarily complex.
Instead, notice that the key insight is to focus on when each car would reach the target if it were alone. If a faster car starts behind a slower car, it may catch up and join the slower car's fleet before reaching the target. But since cars cannot pass each other, once they merge, they travel together at the slower speed.
By calculating the time each car would take to reach the target, and processing cars from the closest to the farthest from the target, we can efficiently determine when fleets form. This avoids brute-force simulation and leverages sorting and simple iteration.
time = (target - position[i]) / speed[i]
. This gives the time each car would take to reach the target if it did not join a fleet.
Example:
target = 12
, position = [10, 8, 0, 5, 3]
, speed = [2, 4, 1, 1, 3]
The Car Fleet problem is elegantly solved by shifting the perspective from simulating car movements to analyzing their arrival times. By sorting cars by position and comparing times to the target, we can efficiently count fleets without unnecessary computation. The key insight is that a car can only form a new fleet if it cannot catch up to the fleet ahead. Sorting and a single pass yield an O(n log n) solution that is both simple and powerful.
class Solution:
def carFleet(self, target: int, position: List[int], speed: List[int]) -> int:
cars = sorted(zip(position, speed), reverse=True)
fleets = 0
curr_time = 0
for pos, spd in cars:
time = (target - pos) / spd
if time > curr_time:
fleets += 1
curr_time = time
return fleets
class Solution {
public:
int carFleet(int target, vector<int>& position, vector<int>& speed) {
vector<pair<int, double>> cars;
int n = position.size();
for (int i = 0; i < n; ++i) {
cars.push_back({position[i], (double)(target - position[i]) / speed[i]});
}
sort(cars.rbegin(), cars.rend());
int fleets = 0;
double curr_time = 0;
for (auto& car : cars) {
if (car.second > curr_time) {
fleets++;
curr_time = car.second;
}
}
return fleets;
}
};
class Solution {
public int carFleet(int target, int[] position, int[] speed) {
int n = position.length;
double[][] cars = new double[n][2];
for (int i = 0; i < n; i++) {
cars[i][0] = position[i];
cars[i][1] = (double)(target - position[i]) / speed[i];
}
Arrays.sort(cars, (a, b) -> Double.compare(b[0], a[0]));
int fleets = 0;
double curr_time = 0;
for (int i = 0; i < n; i++) {
if (cars[i][1] > curr_time) {
fleets++;
curr_time = cars[i][1];
}
}
return fleets;
}
}
var carFleet = function(target, position, speed) {
let cars = position.map((pos, i) => [pos, (target - pos) / speed[i]]);
cars.sort((a, b) => b[0] - a[0]);
let fleets = 0;
let currTime = 0;
for (let [pos, time] of cars) {
if (time > currTime) {
fleets++;
currTime = time;
}
}
return fleets;
};