Builds on Prefix Sum Map and Prefix Sums, which you haven’t finished yet.
Difference Array (Range Updates)
Flights are numbered from 1 to n. A booking [first, last, seats] adds seats reserved seats to each flight from first through last. After all of bookings, report each flight's total: position i of the result holds the seats reserved on flight i + 1.
10 + 20 + 25 = 55, flight 3 gets 20 + 25 = 45, and so on.Difference Array
range updates ➔ +v at the start, -v just past the end ➔ one prefix sum| 1 | def corp_flight_bookings(bookings: list[list[int]], n: int) -> list[int]: |
| 2 | """Corporate Flight Bookings: range adds via a difference array, read once by prefix sum. |
| 3 | Time: O(Q + N) | Space: O(N) |
| 4 | """ |
| 5 | diff = [0] * (n + 1) # One extra slot so last + 1 never overflows |
| 6 | # 1. Mark Each Range's Start And End: |
| 7 | # Adding seats to every flight from first to last only changes the running total at two points: where the range starts, and one past where it ends. |
| 8 | for first, last, seats in bookings: |
| 9 | diff[first - 1] += seats # Range starts here (1-indexed input) |
| 10 | diff[last] -= seats # Range ends after flight `last` |
| 11 | |
| 12 | # 2. Rebuild Every Total With One Prefix Sum: |
| 13 | # running accumulates diff left to right, so it equals the sum of every mark placed at or before i, which is exactly the total booked on flight i + 1. |
| 14 | answer, running = [], 0 |
| 15 | for i in range(n): |
| 16 | running += diff[i] |
| 17 | answer.append(running) |
| 18 | return answer |
diff[0] + ... + diff[i] is the total booked on flight i + 1.Adding seats to every flight from first to last only changes the running total in two places: where the range starts and just after it ends. So record diff[first - 1] += seats and diff[last] -= seats, and one prefix sum over diff at the end rebuilds every flight's total. The trap is the end mark: it goes at diff[last], one past the range in 0-indexed terms, so diff needs n + 1 slots, or a booking that ends on the last flight writes out of bounds.
See it run
Difference Array, step by step
running 0
The top row is diff. The bottom row is the answer. Slot i belongs to flight i + 1, and the last slot belongs to no flight.
start marka slot that gets +seats where a booking startsend marka slot that gets -seats just after a booking endsreadthe diff slot added to running in this steptotalthe finished total of one flight
Start: 5 flights and 3 bookings. diff has 6 slots: one per flight and one extra slot at the end.
Gotcha 1 of 3
- The trap
Gotcha 1: Making
diffonlynslots longMistakediff = [0] * nFixdiff = [0] * (n + 1)What happens: A booking that ends on the last flight writes its end mark at
diff[last], which isdiff[n]. A list ofnslots has indices 0 ton - 1only. So Python raises an IndexError on that write.Example: Corporate Flight Bookings (LC 1109), Example 1: bookings = [[1, 2, 10], [2, 3, 20], [2, 5, 25]], n = 5Mistake: raises IndexErrorFix: returns [10, 55, 45, 25, 25]
- The positions are huge or not whole numbers, as in Meeting Rooms II (LC 253), so you can't allocate one slot per position; sort the start and end events instead. See Sweep Line
- Updates and sum queries arrive mixed together, as in Range Sum Query - Mutable (LC 307), so values must be readable between updates. See Fenwick Tree
Deep Dive
Why two marks describe a whole range
The Prefix Sums card turns a list of values into running totals. A difference array is the reverse. You write marks into diff, and one prefix sum over diff gives the final values.
A booking adds seats to every flight from first to last. In the running total, a +seats mark at the start raises every flight from there on. A -seats mark just after the end cancels it. The flights between the two marks get seats, and the flights after the end get 0.
So each booking costs two writes, whatever the length of its range. All bookings are marked first. Then one pass computes running += diff[i] for every flight. The cost is O(Q + N) for Q bookings and N flights. Adding to every flight of every range costs up to O(Q * N).
The method works because all updates come before any read. If reads are mixed with updates, one prefix sum at the end is not enough. The Fenwick Tree card handles that case.
Corporate Flight Bookings traced
The input is bookings = [[1, 2, 10], [2, 3, 20], [2, 5, 25]] and n = 5. The flights are numbered from 1, and diff is indexed from 0, so flight first is at diff[first - 1].
Booking [1, 2, 10] writes diff[0] += 10 and diff[2] -= 10. Booking [2, 3, 20] writes diff[1] += 20 and diff[3] -= 20. Booking [2, 5, 25] writes diff[1] += 25 and diff[5] -= 25.
The result is diff = [10, 45, -10, -20, 0, -25]. The running totals are 10, 55, 45, 25, 25, which is the answer of the problem.
The last write is diff[5]. A booking that ends on the last flight writes at index n, so diff needs n + 1 slots. With n slots, Python raises an IndexError.
The end mark, and the same card with 0-indexed ranges
The end mark goes one past the last position of the range. In Corporate Flight Bookings (LC 1109), flights are numbered from 1, so the index just past flight last is diff[last]. That is why the card writes diff[last] -= seats.
In Range Addition (LC 370), positions start at 0 and end is the last position of the range. The end mark is diff[end + 1] -= inc. For length = 5 and updates = [[1, 3, 2], [2, 4, 3], [0, 2, -2]], the result is [-2, 0, 3, 5, 3].
In Car Pooling (LC 1094), a trip [passengers, from, to] lets the passengers get off at to. They are in the car at positions from to to - 1. The marks are diff[from] += passengers and diff[to] -= passengers. The car is over capacity if any running total exceeds capacity. For trips = [[2, 1, 5], [3, 5, 7]] and capacity = 3, the answer is True, because the 2 passengers get off at 5 before the 3 get on.
In Shifting Letters II (LC 2381), the mark is +1 for a forward shift and -1 for a backward shift. The running total can be negative or larger than 25, so take the final position modulo 26.
60-Second Pitch
"Every booking adds the same amount to a whole range of flights. If I add it flight by flight, the cost is the length of each range. Instead I write two marks: +seats where the range starts and -seats just after it ends. One prefix sum over these marks then gives the total on every flight. The array has n + 1 slots, because a booking that ends on the last flight writes the end mark at index n. I also convert the 1-indexed flight numbers to list indices. The time is O(Q + N) and the space is O(N). This works because all updates come before the reads."
Common Questions
- Why does one prefix sum over the marks give the right totals?
The running total at flight
i + 1is the sum of all marks at or before it. A+seatsmark counts for every flight from the start of its range. The matching-seatsmark cancels it after the end. So a booking addsseatsonly inside its range.- Why does
diffneedn + 1slots? A booking that ends on the last flight writes its end mark at index
n. A list ofnslots has indices 0 ton - 1, so that write fails. The extra slot is never read for an answer.- How do you handle 0-indexed inclusive ranges, as in Range Addition (LC 370)?
Write
diff[start] += incanddiff[end + 1] -= inc. The end mark goes one position past the last position of the range. Usen + 1slots, or skip the write whenend + 1equalsn.- When is a difference array the wrong tool?
It is wrong when reads come between updates. It is also wrong when the positions are huge numbers or not whole numbers, because one slot per position does not fit in memory. The Sweep Line card sorts the start and end events for that case.
- What is the cost, compared with updating every position?
The marks cost
O(1)per update and the final pass costsO(N), so the total isO(Q + N). Updating every position of every range costs up toO(Q * N).
SWE Reasoning
Spot it
- Many updates each add a value to a whole range, and the values are read only after all updates.
- The question asks for every final value, or for how many ranges cover each point.
- The positions are small whole numbers, so one slot per position fits in memory.
- Example problems: Corporate Flight Bookings (LC 1109), Range Addition (LC 370), Car Pooling (LC 1094).
The invariant, step by step
diffstarts asn + 1zeros.- A booking writes
+seatsatdiff[first - 1]and-seatsatdiff[last]. - The sum
diff[0] + ... + diff[i]counts the+seatsmarks at or before flighti + 1, minus the-seatsmarks at or before it. - A booking is counted exactly when
first - 1 <= iandlast > i, which means flighti + 1is inside its range. - So the sum is the total booked on flight
i + 1, and the looprunning += diff[i]computes it for every flight.
Traps
- Making
diffonlynslots long. A booking that ends on the last flight writes atdiff[n]and raises an IndexError. - Using the 1-indexed flight numbers as list indices. Every booking shifts one flight too late. For
[[1, 2, 10]]andn = 3, the result is[0, 10, 10]instead of[10, 10, 0]. - Putting the end mark on the last position of the range. The
-seatsthen cancels the last flight too early. - Reading values between updates. Marks give correct values only after the prefix sum, so reads and updates cannot be mixed.
Practice
Builds on Prefix Sum Map and Prefix Sums, which you haven’t finished yet.
Difference Array (Range Updates)
Flights are numbered from 1 to n. A booking [first, last, seats] adds seats reserved seats to each flight from first through last. After all of bookings, report each flight's total: position i of the result holds the seats reserved on flight i + 1.
10 + 20 + 25 = 55, flight 3 gets 20 + 25 = 45, and so on.Difference Array
range updates ➔ +v at the start, -v just past the end ➔ one prefix sum| 1 | def corp_flight_bookings(bookings: list[list[int]], n: int) -> list[int]: |
| 2 | """Corporate Flight Bookings: range adds via a difference array, read once by prefix sum. |
| 3 | Time: O(Q + N) | Space: O(N) |
| 4 | """ |
| 5 | diff = [0] * (n + 1) # One extra slot so last + 1 never overflows |
| 6 | # 1. Mark Each Range's Start And End: |
| 7 | # Adding seats to every flight from first to last only changes the running total at two points: where the range starts, and one past where it ends. |
| 8 | for first, last, seats in bookings: |
| 9 | diff[first - 1] += seats # Range starts here (1-indexed input) |
| 10 | diff[last] -= seats # Range ends after flight `last` |
| 11 | |
| 12 | # 2. Rebuild Every Total With One Prefix Sum: |
| 13 | # running accumulates diff left to right, so it equals the sum of every mark placed at or before i, which is exactly the total booked on flight i + 1. |
| 14 | answer, running = [], 0 |
| 15 | for i in range(n): |
| 16 | running += diff[i] |
| 17 | answer.append(running) |
| 18 | return answer |
diff[0] + ... + diff[i] is the total booked on flight i + 1.Adding seats to every flight from first to last only changes the running total in two places: where the range starts and just after it ends. So record diff[first - 1] += seats and diff[last] -= seats, and one prefix sum over diff at the end rebuilds every flight's total. The trap is the end mark: it goes at diff[last], one past the range in 0-indexed terms, so diff needs n + 1 slots, or a booking that ends on the last flight writes out of bounds.
See it run
Difference Array, step by step
running 0
The top row is diff. The bottom row is the answer. Slot i belongs to flight i + 1, and the last slot belongs to no flight.
start marka slot that gets +seats where a booking startsend marka slot that gets -seats just after a booking endsreadthe diff slot added to running in this steptotalthe finished total of one flight
Start: 5 flights and 3 bookings. diff has 6 slots: one per flight and one extra slot at the end.
Gotcha 1 of 3
- The trap
Gotcha 1: Making
diffonlynslots longMistakediff = [0] * nFixdiff = [0] * (n + 1)What happens: A booking that ends on the last flight writes its end mark at
diff[last], which isdiff[n]. A list ofnslots has indices 0 ton - 1only. So Python raises an IndexError on that write.Example: Corporate Flight Bookings (LC 1109), Example 1: bookings = [[1, 2, 10], [2, 3, 20], [2, 5, 25]], n = 5Mistake: raises IndexErrorFix: returns [10, 55, 45, 25, 25]
- The positions are huge or not whole numbers, as in Meeting Rooms II (LC 253), so you can't allocate one slot per position; sort the start and end events instead. See Sweep Line
- Updates and sum queries arrive mixed together, as in Range Sum Query - Mutable (LC 307), so values must be readable between updates. See Fenwick Tree
Deep Dive
Why two marks describe a whole range
The Prefix Sums card turns a list of values into running totals. A difference array is the reverse. You write marks into diff, and one prefix sum over diff gives the final values.
A booking adds seats to every flight from first to last. In the running total, a +seats mark at the start raises every flight from there on. A -seats mark just after the end cancels it. The flights between the two marks get seats, and the flights after the end get 0.
So each booking costs two writes, whatever the length of its range. All bookings are marked first. Then one pass computes running += diff[i] for every flight. The cost is O(Q + N) for Q bookings and N flights. Adding to every flight of every range costs up to O(Q * N).
The method works because all updates come before any read. If reads are mixed with updates, one prefix sum at the end is not enough. The Fenwick Tree card handles that case.
Corporate Flight Bookings traced
The input is bookings = [[1, 2, 10], [2, 3, 20], [2, 5, 25]] and n = 5. The flights are numbered from 1, and diff is indexed from 0, so flight first is at diff[first - 1].
Booking [1, 2, 10] writes diff[0] += 10 and diff[2] -= 10. Booking [2, 3, 20] writes diff[1] += 20 and diff[3] -= 20. Booking [2, 5, 25] writes diff[1] += 25 and diff[5] -= 25.
The result is diff = [10, 45, -10, -20, 0, -25]. The running totals are 10, 55, 45, 25, 25, which is the answer of the problem.
The last write is diff[5]. A booking that ends on the last flight writes at index n, so diff needs n + 1 slots. With n slots, Python raises an IndexError.
The end mark, and the same card with 0-indexed ranges
The end mark goes one past the last position of the range. In Corporate Flight Bookings (LC 1109), flights are numbered from 1, so the index just past flight last is diff[last]. That is why the card writes diff[last] -= seats.
In Range Addition (LC 370), positions start at 0 and end is the last position of the range. The end mark is diff[end + 1] -= inc. For length = 5 and updates = [[1, 3, 2], [2, 4, 3], [0, 2, -2]], the result is [-2, 0, 3, 5, 3].
In Car Pooling (LC 1094), a trip [passengers, from, to] lets the passengers get off at to. They are in the car at positions from to to - 1. The marks are diff[from] += passengers and diff[to] -= passengers. The car is over capacity if any running total exceeds capacity. For trips = [[2, 1, 5], [3, 5, 7]] and capacity = 3, the answer is True, because the 2 passengers get off at 5 before the 3 get on.
In Shifting Letters II (LC 2381), the mark is +1 for a forward shift and -1 for a backward shift. The running total can be negative or larger than 25, so take the final position modulo 26.
60-Second Pitch
"Every booking adds the same amount to a whole range of flights. If I add it flight by flight, the cost is the length of each range. Instead I write two marks: +seats where the range starts and -seats just after it ends. One prefix sum over these marks then gives the total on every flight. The array has n + 1 slots, because a booking that ends on the last flight writes the end mark at index n. I also convert the 1-indexed flight numbers to list indices. The time is O(Q + N) and the space is O(N). This works because all updates come before the reads."
Common Questions
- Why does one prefix sum over the marks give the right totals?
The running total at flight
i + 1is the sum of all marks at or before it. A+seatsmark counts for every flight from the start of its range. The matching-seatsmark cancels it after the end. So a booking addsseatsonly inside its range.- Why does
diffneedn + 1slots? A booking that ends on the last flight writes its end mark at index
n. A list ofnslots has indices 0 ton - 1, so that write fails. The extra slot is never read for an answer.- How do you handle 0-indexed inclusive ranges, as in Range Addition (LC 370)?
Write
diff[start] += incanddiff[end + 1] -= inc. The end mark goes one position past the last position of the range. Usen + 1slots, or skip the write whenend + 1equalsn.- When is a difference array the wrong tool?
It is wrong when reads come between updates. It is also wrong when the positions are huge numbers or not whole numbers, because one slot per position does not fit in memory. The Sweep Line card sorts the start and end events for that case.
- What is the cost, compared with updating every position?
The marks cost
O(1)per update and the final pass costsO(N), so the total isO(Q + N). Updating every position of every range costs up toO(Q * N).
SWE Reasoning
Spot it
- Many updates each add a value to a whole range, and the values are read only after all updates.
- The question asks for every final value, or for how many ranges cover each point.
- The positions are small whole numbers, so one slot per position fits in memory.
- Example problems: Corporate Flight Bookings (LC 1109), Range Addition (LC 370), Car Pooling (LC 1094).
The invariant, step by step
diffstarts asn + 1zeros.- A booking writes
+seatsatdiff[first - 1]and-seatsatdiff[last]. - The sum
diff[0] + ... + diff[i]counts the+seatsmarks at or before flighti + 1, minus the-seatsmarks at or before it. - A booking is counted exactly when
first - 1 <= iandlast > i, which means flighti + 1is inside its range. - So the sum is the total booked on flight
i + 1, and the looprunning += diff[i]computes it for every flight.
Traps
- Making
diffonlynslots long. A booking that ends on the last flight writes atdiff[n]and raises an IndexError. - Using the 1-indexed flight numbers as list indices. Every booking shifts one flight too late. For
[[1, 2, 10]]andn = 3, the result is[0, 10, 10]instead of[10, 10, 0]. - Putting the end mark on the last position of the range. The
-seatsthen cancels the last flight too early. - Reading values between updates. Marks give correct values only after the prefix sum, so reads and updates cannot be mixed.