Sweep and Ranges
What is this?
A bus route has forty stops and a hundred bookings, each covering a stretch of the journey. To check the bus never exceeds capacity you could add every booking's passengers to every stop it covers — thousands of updates. Or you could note, at each stop, only the change: passengers boarding, passengers leaving. Walk the route once adding up the changes, and the running total at every stop is the load.
That is the difference-array idea, and it is the same instinct as grouping consecutive numbers into ranges: the interesting information lives at the boundaries.
(end exclusive)"] B --> D["a run ends when the next value
is not consecutive"] C --> E["one prefix-sum pass
reconstructs every position"] D --> F["emit [start, previous] and open a new run"]
💡 Fun fact: the difference array is the discrete derivative, and the prefix-sum pass that reconstructs the timeline is the discrete integral. Recording
+vand−vat two boundaries is exactly differentiating a step function, and integrating it back recovers the original. That is whykrange updates over a timeline of lengthncostO(k + n)rather thanO(k · n)— you never touch the interior of a range, only its two edges.
🔓 The 2 problems in this chapter are free. Sign in with Google or Microsoft to start solving.
The one-line idea: never touch the inside of a range. Record what changes at its two edges, make one ordered pass, and let the accumulation reconstruct everything in between.
1. The difference array
delta = [0] * (max_position + 1)
for passengers, start, end in trips:
delta[start] += passengers
delta[end] -= passengers # end is EXCLUSIVE — they get off here
load = 0
for stop in range(len(delta)):
load += delta[stop]
if load > capacity:
return False
return True
The exclusive end is the whole correctness argument. A passenger travelling [2, 5) is aboard at stops 2, 3 and 4 but not at 5 — so writing −v at 5 rather than 6 is what stops back-to-back trips being double-counted. Getting this wrong produces answers that are right for isolated ranges and wrong the moment two ranges touch.
2. Run grouping
ranges, i, n = [], 0, len(nums)
while i < n:
start = i
while i + 1 < n and nums[i + 1] == nums[i] + 1:
i += 1 # extend while consecutive
ranges.append(str(start_val) if start == i else f"{nums[start]}->{nums[i]}")
i += 1
Two details cause most bugs here. The single-element case formats differently ("4", not "4->4"), and the final run must be emitted after the loop ends — there is no "next value" to trigger its closure.
3. A 30-second worked example (car pooling)
Trips (2 passengers, 1→5), (3 passengers, 3→7), capacity 4:
delta: index 0 1 2 3 4 5 6 7
0 +2 0 +3 0 -2 0 -3
sweep:
stop 1 → load 2 ✓
stop 3 → load 5 ✗ exceeds capacity 4 → return False
The two trips overlap on stops 3 and 4, and the running total exposes that at stop 3 without ever enumerating which trips are aboard. With capacity 5 the same sweep would return True.
4. Where you'll actually meet this
- Capacity checks. Vehicle occupancy, room bookings and connection pools — anything where claims overlap in time.
- Monitoring and alerting. Counting concurrent requests over a window without storing each one.
- Genomics. Coverage depth along a reference sequence is a difference array over read alignments.
- Billing and metering. Aggregating overlapping usage windows into a per-interval total.
- Data compression and display. Collapsing consecutive identifiers into ranges —
1-5, 8, 11-14— in page selectors and log summaries.
5. Problems in this chapter
▶ Summary Ranges
Compress a sorted array into range strings. One pass holding the start of the current run, closing it when the chain breaks, and flushing the final run afterwards.
Pattern: run grouping. Target: O(n) time, O(1) extra space.
▶ Car Pooling
Decide whether a vehicle's capacity is ever exceeded. Difference array over the route, then a prefix-sum sweep checking the running load.
Pattern: difference array + prefix sum. Target: O(k + n) time, O(n) space.
6. Common pitfalls 🚫
- Using an inclusive end.
−vmust land atend, notend + 1, or touching trips double-count. - Forgetting the last run. Nothing triggers its closure inside the loop, so it must be emitted afterwards.
- Formatting single elements as a range.
"4", not"4->4". - Sizing the delta array too small. It needs one slot past the maximum coordinate.
- Sorting trips before sweeping. Unnecessary when coordinates are bounded — index directly. Sorting only helps when coordinates are sparse or huge.
- Checking capacity after the sweep. The limit must be tested at every stop, since the peak may occur mid-route.
- Assuming the input is sorted in Summary Ranges. It is stated as sorted; if it were not, that assumption would silently produce wrong ranges.
7. Key takeaways
- Record deltas, not values. Two point writes replace a whole range update.
- The end is exclusive. That single convention is what keeps adjacent ranges honest.
- One prefix-sum pass reconstructs the timeline, and the running total answers the question at every point.
- Close the final run after the loop.
- Bounded coordinates mean direct indexing; sparse or huge ones mean sorting the events instead.
- This is the counting cousin of merging. Merging asks which intervals overlap; sweeping asks how many.
- Why interviewers like it: the naive per-position update is the obvious answer and is quadratic. Reaching for boundaries instead is a small, transferable insight they can test in ten minutes.
Order: Summary Ranges → Car Pooling.
Car Pooling
Core idea: Every trip is two events on a one-dimensional road: passengers board at
from(+num) and alight atto(-num). Lay those deltas on a number line, then sweep left to right keeping a running sum — the current occupancy of the car. If that running occupancy ever exceedscapacity, the trips don't fit. This is a difference array: record+numatfromand-numatto, take the prefix sum, and watch the maximum.
The problem, rephrased
You're driving a van that only ever moves east — it can pick up and drop off, but it never turns around. You start at kilometer 0 with capacity empty seats. You're handed a fixed list of bookings up front; each booking is [numPassengers, from, to], meaning that group boards at kilometer from and leaves at kilometer to (with from < to, measured as kilometers east of your start).
Return True if you can honor every booking without ever having more passengers aboard than the van holds, and False otherwise.
Because the van only drives forward, a passenger occupies a seat exactly over the half-open interval [from, to) — they free the seat the moment you reach to, which is before anyone boarding at to takes it. So overlapping intervals stack their passenger counts, and the question reduces to: does the peak simultaneous occupancy ever exceed capacity?
A worked input/output
| trips | capacity | Output | Why |
|---|---|---|---|
[[2,1,5],[3,3,7]] |
4 | False | Between km 3 and km 5 both groups overlap → 2 + 3 = 5 aboard > 4. |
[[2,1,5],[3,3,7]] |
5 | True | Same overlap peaks at 5, which now fits exactly. |
[[2,1,5],[3,5,7]] |
3 | True | First group leaves at km 5, exactly when the second boards — no overlap, peak is 3. |
[[3,2,7],[3,7,9],[8,3,9]] |
11 | True | Peak overlap is 3 + 8 = 11 over km 3–7, fits exactly. |
Notice the answer hinges entirely on the maximum overlap of the passenger intervals — never on the order trips were listed.
Sign in to continue reading
The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.
Sign in to read the full lesson