Car Pooling
Description
You have a car with a fixed number of empty seats, given by capacity. The car travels only eastward along a straight road — it cannot turn around.
You are given an array trips where each element trips[i] = [numPassengers, from, to] describes a single trip:
numPassengerspassengers need to be picked up at kilometrefrom.- Those passengers must be dropped off at kilometre
to.
The car picks up passengers at the from location and drops them off at the to location (they are no longer in the car at to).
Return true if it is possible to complete all trips without ever exceeding the car's capacity at any point along the route. Return false otherwise.
Examples
Example 1
Input: trips = [[2,1,5],[3,3,7]], capacity = 4
Output: false
Explanation: At kilometre 1, we pick up 2 passengers (car has 2). At kilometre 3, we pick up 3 more (car now has 5). But 5 exceeds the capacity of 4, so we cannot complete all trips.
Example 2
Input: trips = [[2,1,5],[3,3,7]], capacity = 5
Output: true
Explanation: At kilometre 1, pick up 2 passengers (car has 2). At kilometre 3, pick up 3 more (car has 5, which equals the capacity — still valid). At kilometre 5, drop off the first 2 (car has 3). At kilometre 7, drop off the remaining 3 (car has 0). The capacity is never exceeded.
Example 3
Input: trips = [[3,2,7],[3,7,9],[8,3,9]], capacity = 11
Output: true
Explanation: At km 2, pick up 3 (car has 3). At km 3, pick up 8 (car has 11, equals capacity). At km 7, drop off the first 3 AND pick up 3 new ones (the drop-off happens first conceptually since passengers leave at their destination). Car has 11. At km 9, drop off 3 + 8 = 11 (car has 0). Capacity is never exceeded.
Constraints
- 1 ≤ trips.length ≤ 1000
- trips[i].length == 3
- 1 ≤ numPassengers ≤ 100
- 0 ≤ from < to ≤ 1000
- 1 ≤ capacity ≤ 10^5
Editorial
Brute Force
Intuition
The most direct way to think about this problem is to simulate the car's journey kilometre by kilometre. At each location along the route, count how many passengers are currently in the car, and check whether that count exceeds the capacity.
Imagine you are driving a shuttle bus down a straight road. At every kilometre marker, you look at your manifest: which trips have started but not yet ended at this point? You add up those passengers and make sure you are not overloaded.
For each location from 0 to the farthest drop-off, we loop through all trips and check whether the location falls within the trip's active range — that is, from ≤ location < to. If it does, we add the trip's passenger count to the running total for that location.
Step-by-Step Explanation
Let us trace with trips = [[2,1,5],[3,3,7]], capacity = 4.
Step 1: Find the maximum drop-off location: max(5, 7) = 7. We check locations 0 through 6 (passengers leave AT the drop-off, so they are in the car from from to to - 1).
Step 2: Location 0 — For trip [2,1,5]: 0 < 1, not active. For trip [3,3,7]: 0 < 3, not active. Passengers = 0. OK.
Step 3: Location 1 — For trip [2,1,5]: 1 ≥ 1 and 1 < 5, active → +2. For trip [3,3,7]: 1 < 3, not active. Passengers = 2 ≤ 4. OK.
Step 4: Location 2 — Trip [2,1,5] active → +2. Trip [3,3,7] not active. Passengers = 2 ≤ 4. OK.
Step 5: Location 3 — Trip [2,1,5]: 3 ≥ 1 and 3 < 5, active → +2. Trip [3,3,7]: 3 ≥ 3 and 3 < 7, active → +3. Passengers = 5. 5 > 4 — EXCEEDS CAPACITY!
Step 6: We found a violation at location 3. Return false immediately.
Result: false — the car cannot handle all trips with capacity 4.
Brute Force Simulation — Checking Passengers at Each Location — Watch how we check every location along the route, summing up active trips at each point to determine whether the car's capacity is exceeded.
Algorithm
- Find the maximum drop-off location M across all trips.
- For each location
locfrom 0 to M - 1:
a. Initializepassengers = 0.
b. For each trip[num, from, to]:- If
from ≤ loc < to, addnumtopassengers.
c. Ifpassengers > capacity, returnfalse.
- If
- If no location exceeds capacity, return
true.
Code
class Solution {
public:
bool carPooling(vector<vector<int>>& trips, int capacity) {
int maxLoc = 0;
for (auto& t : trips) {
maxLoc = max(maxLoc, t[2]);
}
for (int loc = 0; loc < maxLoc; loc++) {
int passengers = 0;
for (auto& t : trips) {
if (t[1] <= loc && loc < t[2]) {
passengers += t[0];
}
}
if (passengers > capacity) return false;
}
return true;
}
};class Solution:
def carPooling(self, trips: list[list[int]], capacity: int) -> bool:
max_loc = max(t[2] for t in trips)
for loc in range(max_loc):
passengers = 0
for num, frm, to in trips:
if frm <= loc < to:
passengers += num
if passengers > capacity:
return False
return Trueclass Solution {
public boolean carPooling(int[][] trips, int capacity) {
int maxLoc = 0;
for (int[] t : trips) {
maxLoc = Math.max(maxLoc, t[2]);
}
for (int loc = 0; loc < maxLoc; loc++) {
int passengers = 0;
for (int[] t : trips) {
if (t[1] <= loc && loc < t[2]) {
passengers += t[0];
}
}
if (passengers > capacity) return false;
}
return true;
}
}Complexity Analysis
Time Complexity: O(M · n)
Where M is the maximum drop-off location (up to 1000) and n is the number of trips (up to 1000). For every location we scan all trips, giving up to 1,000,000 operations in the worst case. This is acceptable for the given constraints but far from optimal.
Space Complexity: O(1)
We only use a few integer variables. No additional data structures are needed.
Why This Approach Is Not Efficient
The brute force checks every (location, trip) pair, doing O(M · n) work. Most of this work is wasted — at a given location, most trips are not active, but we still inspect every single one.
The fundamental inefficiency is that we recount passengers from scratch at every location. If we knew how the passenger count changes from one location to the next, we could process the changes incrementally instead of re-summing everything.
Key insight: the passenger count only changes at event points — pickup locations (count goes up) and drop-off locations (count goes down). Between events, the count stays the same. We can sort these events and sweep through them, which avoids rechecking inactive trips.
Better Approach - Sort Events and Sweep
Intuition
Instead of checking every location, we only care about the points where passengers get on or off. We can model each trip as two events:
- A pickup event at location
from: the passenger count increases bynumPassengers. - A drop-off event at location
to: the count decreases bynumPassengers.
Think of a bus schedule board. Instead of watching the bus at every kilometre, you just look at the stops. At each stop, you note who gets on and who gets off, then update the running total.
We collect all these events, sort them by location, and sweep through in order. At each event, we update a running passenger count and check if it exceeds the capacity. Sorting ensures we process events left to right along the route.
An important detail: when a pickup and a drop-off happen at the same location, the drop-off should be processed first (passengers leave before new ones board). This is handled naturally because the problem states passengers are no longer in the car at their to location.
Step-by-Step Explanation
Let us trace with trips = [[2,1,5],[3,3,7]], capacity = 4.
Step 1: Create events from each trip:
- Trip [2,1,5] → event (loc=1, +2) and event (loc=5, -2).
- Trip [3,3,7] → event (loc=3, +3) and event (loc=7, -3).
- All events: [(1,+2), (3,+3), (5,-2), (7,-3)].
Step 2: Sort events by location (already sorted here): [(1,+2), (3,+3), (5,-2), (7,-3)].
Step 3: Start sweep with current_passengers = 0.
Step 4: Process event (1, +2): current_passengers = 0 + 2 = 2. Check: 2 ≤ 4? Yes. OK.
Step 5: Process event (3, +3): current_passengers = 2 + 3 = 5. Check: 5 ≤ 4? NO — exceeds capacity!
Step 6: Return false immediately.
Result: false.
Event Sweep — Processing Pickups and Drop-offs in Order — Watch how we convert trips into sorted events and sweep through them, maintaining a running passenger count that reveals capacity violations.
Algorithm
- Create a list of events. For each trip
[num, from, to]:- Add event
(from, +num)(pickup). - Add event
(to, -num)(drop-off).
- Add event
- Sort events by location. If two events share the same location, process drop-offs (negative) before pickups (positive).
- Initialize
current_passengers = 0. - For each event
(loc, change):- Update
current_passengers += change. - If
current_passengers > capacity, returnfalse.
- Update
- Return
true.
Code
class Solution {
public:
bool carPooling(vector<vector<int>>& trips, int capacity) {
vector<pair<int,int>> events;
for (auto& t : trips) {
events.push_back({t[1], t[0]}); // pickup
events.push_back({t[2], -t[0]}); // drop-off
}
// Sort by location; at same location, drop-offs before pickups
sort(events.begin(), events.end(), [](auto& a, auto& b) {
return a.first == b.first ? a.second < b.second : a.first < b.first;
});
int passengers = 0;
for (auto& [loc, change] : events) {
passengers += change;
if (passengers > capacity) return false;
}
return true;
}
};class Solution:
def carPooling(self, trips: list[list[int]], capacity: int) -> bool:
events = []
for num, frm, to in trips:
events.append((frm, num)) # pickup
events.append((to, -num)) # drop-off
# Sort by location; at same location, drop-offs (negative) first
events.sort(key=lambda x: (x[0], x[1]))
passengers = 0
for loc, change in events:
passengers += change
if passengers > capacity:
return False
return Trueclass Solution {
public boolean carPooling(int[][] trips, int capacity) {
List<int[]> events = new ArrayList<>();
for (int[] t : trips) {
events.add(new int[]{t[1], t[0]}); // pickup
events.add(new int[]{t[2], -t[0]}); // drop-off
}
// Sort by location; at same location, drop-offs first
events.sort((a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
int passengers = 0;
for (int[] event : events) {
passengers += event[1];
if (passengers > capacity) return false;
}
return true;
}
}Complexity Analysis
Time Complexity: O(n log n)
We create 2n events and sort them, costing O(n log n). The sweep through sorted events is O(n). The sort dominates.
Space Complexity: O(n)
We store 2n events in a list.
Why This Approach Is Not Efficient
The event sweep runs in O(n log n) due to sorting, which is already very efficient. However, we can observe that the problem has a special property: all locations are integers in a bounded range (0 ≤ location ≤ 1000). When the range of values is small and fixed, we can avoid comparison-based sorting entirely.
Instead of sorting events, we can use a difference array — a fixed-size array indexed by location — to record the net passenger change at each point. Then a single prefix-sum pass over this array gives us the passenger count at every location. This eliminates the O(n log n) sorting step and reduces the total time to O(n + M), where M is the maximum location value (at most 1000).
Optimal Approach - Difference Array
Intuition
Instead of creating event objects and sorting them, we can use the difference array technique. The idea is elegantly simple:
- Create an array
diffof size M+1 (where M is the farthest drop-off), initialised to all zeros. - For each trip
[num, from, to]:- Add
+numat indexfrom(passengers board). - Add
-numat indexto(passengers exit).
- Add
- Compute the prefix sum of
diff. At each index, the prefix sum tells you the exact number of passengers in the car at that location. - If the prefix sum ever exceeds capacity, return
false.
Think of the diff array as a ledger that records only the changes — not the totals. "At km 1, add 2 passengers. At km 5, remove 2 passengers." The prefix sum converts these changes back into running totals.
This technique works because passengers board at a single point and exit at a single point, and the locations are small integers — perfect for array indexing.

Step-by-Step Explanation
Let us trace with trips = [[2,1,5],[3,3,7]], capacity = 4.
Step 1: Find max drop-off: max(5, 7) = 7. Create diff array of size 8 (indices 0..7), all zeros: [0, 0, 0, 0, 0, 0, 0, 0].
Step 2: Process trip [2, 1, 5]: diff[1] += 2, diff[5] -= 2. Array: [0, 2, 0, 0, 0, -2, 0, 0].
Step 3: Process trip [3, 3, 7]: diff[3] += 3, diff[7] -= 3. Array: [0, 2, 0, 3, 0, -2, 0, -3].
Step 4: Compute prefix sum and check. Start with running_sum = 0.
- Index 0: running_sum = 0 + 0 = 0. ≤ 4? Yes.
- Index 1: running_sum = 0 + 2 = 2. ≤ 4? Yes.
- Index 2: running_sum = 2 + 0 = 2. ≤ 4? Yes.
- Index 3: running_sum = 2 + 3 = 5. ≤ 4? NO — exceeds capacity!
Step 5: Return false.
Result: false — same answer, but computed without sorting and without checking inactive trips.
Difference Array — Record Changes, Compute Prefix Sum, Check Capacity — Watch how we record passenger changes in a difference array, then sweep with a prefix sum to find the exact passenger count at each location.
Algorithm
- Find the maximum drop-off location M.
- Create an integer array
diffof size M + 1, initialised to zeros. - For each trip
[num, from, to]:diff[from] += num(passengers board).diff[to] -= num(passengers exit).
- Compute the prefix sum of
diff. At each index, check whether the prefix sum exceedscapacity.- If it does, return
false.
- If it does, return
- If the entire prefix sum stays within capacity, return
true.
Code
class Solution {
public:
bool carPooling(vector<vector<int>>& trips, int capacity) {
int maxLoc = 0;
for (auto& t : trips) {
maxLoc = max(maxLoc, t[2]);
}
vector<int> diff(maxLoc + 1, 0);
for (auto& t : trips) {
diff[t[1]] += t[0]; // passengers board
diff[t[2]] -= t[0]; // passengers exit
}
int passengers = 0;
for (int i = 0; i <= maxLoc; i++) {
passengers += diff[i];
if (passengers > capacity) return false;
}
return true;
}
};from itertools import accumulate
class Solution:
def carPooling(self, trips: list[list[int]], capacity: int) -> bool:
max_loc = max(t[2] for t in trips)
diff = [0] * (max_loc + 1)
for num, frm, to in trips:
diff[frm] += num # passengers board
diff[to] -= num # passengers exit
return all(s <= capacity for s in accumulate(diff))class Solution {
public boolean carPooling(int[][] trips, int capacity) {
int maxLoc = 0;
for (int[] t : trips) {
maxLoc = Math.max(maxLoc, t[2]);
}
int[] diff = new int[maxLoc + 1];
for (int[] t : trips) {
diff[t[1]] += t[0]; // passengers board
diff[t[2]] -= t[0]; // passengers exit
}
int passengers = 0;
for (int i = 0; i <= maxLoc; i++) {
passengers += diff[i];
if (passengers > capacity) return false;
}
return true;
}
}Complexity Analysis
Time Complexity: O(n + M)
Where n is the number of trips and M is the maximum drop-off location. We iterate through all trips once to populate the difference array (O(n)), then sweep through the array to compute the prefix sum (O(M)). Since M ≤ 1000 is bounded by the constraints, the effective time complexity is O(n).
Space Complexity: O(M)
The difference array has M + 1 entries. Since M ≤ 1000, this is at most 1001 integers — effectively constant space relative to n. No sorting is needed, no event objects are created.