diff --git a/README.md b/README.md index 67b1f4d..a584448 100644 --- a/README.md +++ b/README.md @@ -25,4 +25,5 @@ | 0238 | Medium | Product of Array Except Self | Array | [solution](./docs/0238-Product-Of-Array-Except-Self.md) | | 0242 | Easy | Valid Anagram | String, HashTable | [solution](./docs/0242-Valid-Anagram.md) | | 0347 | Medium | Top K Frequent Elements | Array, HashMap, Bucket Sort | [Solution](./docs/0347-Top-K-Frequent-Elements.md) | -| 0739 | Medium | Daily Temperatures | Array, Stack, Monotonic Stack | [solution](./docs/0139-Daily-Temperatures.md) | \ No newline at end of file +| 0739 | Medium | Daily Temperatures | Array, Stack, Monotonic Stack | [solution](./docs/0139-Daily-Temperatures.md) | +| 0853 | Medium | Car Fleet | Array, Stack, Sorting, Monotonic Stack | [solution](./docs/0853-Car-Fleet.md) | \ No newline at end of file diff --git a/docs/0853-Car-Fleet.md b/docs/0853-Car-Fleet.md new file mode 100644 index 0000000..65a9d7a --- /dev/null +++ b/docs/0853-Car-Fleet.md @@ -0,0 +1,39 @@ +# [Car Fleet](https://leetcode.com/problems/car-fleet/description/) + +## Intuition + +The problem is essentially about determining how many distinct groups (“fleets”) of cars will arrive at a target +destination, given that no car can overtake another but can form groups with any car it catches up to. The critical +insight here is to understand that cars closer to the destination at the start can only form a fleet with cars behind +them if those cars do not catch up by the target. Thus, sorting cars by their starting positions in descending order +allows us to simulate their journey and determine how many separate groups form by the time they reach the target. + +## Approach + +1. **Structuring the Data:** Use a record `PositionSpeed` to store each car’s starting position and speed. This helps in +organizing the data and simplifies operations on it. +2. **Sorting:** Sort the cars based on their starting positions in descending order. This way, we process cars that are +further from the destination first and keep adding cars to a fleet until a car cannot catch up, thus forming a distinct +fleet. +3. **Calculating Arrival Times:** For each car, calculate the time it would take to reach the target from its starting +position at its given speed. This is given by `(target - position) / speed`. +4. **Using a Stack to Form Fleets:** + - Utilize a stack to track the leading arrival times of each fleet. If a car’s calculated arrival time is greater + than the time on the stack (i.e., it takes longer to reach the destination than the car at the top of the stack), it + starts a new fleet, and its time gets pushed onto the stack. + - If a car can catch up (i.e., its arrival time is less than or equal to the time on the top of the stack), it joins + an existing fleet and does not change the stack. +5. **Determining the Number of Fleets:** The number of distinct arrival times in the stack at the end of the iteration +gives the number of fleets. + +## Complexity + +- ** Time Complexity: `O(NlogN)`**. The dominant factor here is the sorting step, which is `O(NlogN)`, where `N` is the +number of cars. +- **Space Complexity: `O(N)`** since we need space proportional to the number of cars for storing the `PositionSpeed` +records, the sorted list, and the stack that potentially can hold as many elements as there are cars in the worst-case +scenario. + +## Code + +- [Java](../src/main/java/io/dksifoua/leetcode/carfleet/Solution.java) \ No newline at end of file diff --git a/src/main/java/io/dksifoua/leetcode/carfleet/Solution.java b/src/main/java/io/dksifoua/leetcode/carfleet/Solution.java new file mode 100644 index 0000000..eb96d8c --- /dev/null +++ b/src/main/java/io/dksifoua/leetcode/carfleet/Solution.java @@ -0,0 +1,28 @@ +package io.dksifoua.leetcode.carfleet; + +import java.util.*; + +public class Solution { + + private record PositionSpeed(int position, int speed) {}; + + public int carFleet(int target, int[] position, int[] speed) { + List positionSpeeds = new ArrayList<>() {{ + for (int i = 0; i < position.length; i++) { + add(new PositionSpeed(position[i], speed[i])); + } + }}; + positionSpeeds.sort(Comparator.comparingInt(PositionSpeed::position).reversed()); + + Stack fleetHeads = new Stack<>(); + for (PositionSpeed positionSpeed: positionSpeeds) { + float time = (float) (target - positionSpeed.position()) / positionSpeed.speed(); + if (fleetHeads.isEmpty() || time > fleetHeads.peek()) { + fleetHeads.push(time); + } + } + System.out.println(fleetHeads); + + return fleetHeads.size(); + } +} diff --git a/src/test/java/io/dksifoua/leetcode/carfleet/SolutionTest.java b/src/test/java/io/dksifoua/leetcode/carfleet/SolutionTest.java new file mode 100644 index 0000000..8ba54cc --- /dev/null +++ b/src/test/java/io/dksifoua/leetcode/carfleet/SolutionTest.java @@ -0,0 +1,29 @@ +package io.dksifoua.leetcode.carfleet; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class SolutionTest { + + public final Solution solution = new Solution(); + + @Test + void test1() { + Assertions.assertEquals(3, solution.carFleet(12, new int[] { 10, 8, 0, 5, 3 }, new int[] { 2, 4, 1, 1, 3 })); + } + + @Test + void test2() { + Assertions.assertEquals(1, solution.carFleet(10, new int[] { 3 }, new int[] { 3 })); + } + + @Test + void test3() { + Assertions.assertEquals(1, solution.carFleet(100, new int[] { 0, 2, 4 }, new int[] { 4, 2, 1 })); + } + + @Test + void test4() { + Assertions.assertEquals(2, solution.carFleet(10, new int[] { 6, 8 }, new int[] { 3, 2 })); + } +}