1109. Corporate Flight Bookings
Problem Description
In this problem, we are managing a system that tracks flight bookings. We are given n
flights, which are identified by numbers ranging from 1
to n
. Additionally, we are provided with an array named bookings
. Each entry in this array is another array that contains three elements, [first_i, last_i, seats_i]
. This entry indicates a booking for multiple flights - from flight number first_i
to flight number last_i
(inclusive) - and each flight in this range has seats_i
seats reserved.
The task is to compute and return an array, answer
, which has the same length as the number of flights (n
). Each element in answer
should represent the total number of seats booked for the corresponding flight. In other words, answer[i]
should tell us how many seats have been reserved for the ith flight.
Intuition
The key to solving this problem is recognizing that the range update operation (booking seats for a range of flights) can be efficiently tracked using the concept of difference arrays. A difference array can allow us to apply the effects of a range update in constant time and later reconstruct the original array with the complete effects applied.
The intuition behind using a difference array is as follows:
- When seats are booked from flight
first_i
tolast_i
, we do not necessarily need to addseats_i
to each entry betweenfirst_i
andlast_i
in the answer array. Instead, we could record theseats_i
addition at the start indexfirst_i - 1
(since arrays are zero-indexed) and a negation ofseats_i
at the indexlast_i
, indicating the end of the booking range. - What this achieves is a sort of "bookend" model, where we place a marker for where seats start being added and where they stop. This is somewhat akin to noting down the start and end of a chalk mark without having to color in the whole segment.
Once we have made these updates to our answer array, which now serves as a difference array, we need to accumulate the effects to find out the total number of seats booked for each flight. Accumulating from left to right will add seats_i
from the start index up until the end index, effectively applying the range update.
- For example, if we add 10 seats at index 0 (flight 1) and subtract 10 seats at index 5 (after flight 5), accumulating the values will result in each of the first 5 elements showing an increment of 10, and the increment will no longer apply from position 6 onward.
- The key operation to accomplish the accumulation efficiently in our Python code is to utilize the
accumulate
function from theitertools
module.
This approach takes us from a brute-force method that might involve multiple iterations per booking (which would be inefficient and potentially time-consuming for a large number of bookings or flights) to a much more efficient algorithm with a time complexity that is linear with respect to the number of flights and bookings.
Learn more about Prefix Sum patterns.
Solution Approach
Let's break down the implementation provided in the reference solution and see how it applies the intuition that we discussed above.
-
Initialize an array
ans
of zeros with the same length as the number of flights (n
). This array will serve as our difference array where we'll apply the updates from the bookings and later accumulate these updates to get the final answer.ans = [0] * n
-
Iterate over each booking in the bookings array. For each booking:
- Increase the element at the index (
first - 1
) in theans
byseats
. This corresponds to the start of the booking range where the seats begin to be reserved. - If the last flight in the booking is not the very last flight available, then decrease the element at the index
last
in theans
byseats
. This will indicate the end of the booking range where the reserved seats are no longer available.
for first, last, seats in bookings: ans[first - 1] += seats if last < n: ans[last] -= seats
- Increase the element at the index (
-
Use the
accumulate
function to accumulate the elements ofans
. This Python function takes a list and returns a list where each element is the cumulative total from the first element to the current one. This effectively reconstructs the resulting array where each element represents the total number of seats reserved for the corresponding flight after applying all bookings. Since theans
array at this stage is a difference array, the accumulation will give us the true number of seats reserved for each flight.return list(accumulate(ans))
In terms of data structures, the problem makes essential use of an array data structure. The algorithmic pattern used here is the "difference array" pattern, which enables us to efficiently apply range updates (in O(1) time) and then reconstruct the original array with a single pass to accumulate these changes (in O(n) time).
The overall algorithm can be summarized in the following steps:
- Initialize a difference array with zeros
- Apply the range update operations to the difference array
- Accumulate the difference array to reconstruct the final answer
This approach is much more efficient than directly applying increments to a range of elements within the array for each booking, especially when dealing with a large number of flights and bookings.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's use a small example to illustrate the solution approach.
Suppose we have n = 5
flights, and we receive the following bookings: [[1, 2, 10], [2, 3, 20], [3, 5, 25]]
. This means:
- 10 seats are booked for flights 1 and 2.
- 20 seats are booked for flights 2 and 3.
- 25 seats are booked for flights 3 to 5 (inclusive).
We start with an array ans
initialized with zeros, with the same length as the number of flights (n
), thus ans = [0, 0, 0, 0, 0]
.
Now, we iterate over each booking and update the ans
array:
-
For the first booking
[1, 2, 10]
, we add 10 seats at index 0 and subtract 10 seats at index 2.- Before:
ans = [0, 0, 0, 0, 0]
- After:
ans = [10, 0, -10, 0, 0]
- Before:
-
For the second booking
[2, 3, 20]
, we add 20 seats at index 1 and subtract 20 seats at index 3.- Before:
ans = [10, 0, -10, 0, 0]
- After:
ans = [10, 20, -10, -20, 0]
- Before:
-
For the third booking
[3, 5, 25]
, we add 25 seats at index 2 and there is no need to subtract at the end since the booking range includes the last flight.- Before:
ans = [10, 20, -10, -20, 0]
- After:
ans = [10, 20, 15, -20, 0]
- Before:
Finally, we use the accumulate
function to build the answer from the ans
difference array:
- Accumulate:
[10, 30, 45, 25, 25]
- This means the total number of seats booked for each flight is 10, 30, 45, 25, and 25, respectively.
The final result of our algorithm gives us the array [10, 30, 45, 25, 25]
, which indicates the total number of seats reserved for each flight from 1 to 5 after all the bookings have been applied.
This example demonstrates the effectiveness of the difference array pattern in managing range updates efficiently. By applying incremental updates at the start and a decremental update at the end of each booking range, we avoid multiple iterations over the range for each booking. Once all the incremental and decremental updates are applied, accumulating the changes provides the total number of booked seats for each flight.
Solution Implementation
1from typing import List
2from itertools import accumulate
3
4class Solution:
5 def corpFlightBookings(self, bookings: List[List[int]], n: int) -> List[int]:
6 # Initialize a result list to hold the number of seats booked for each flight
7 flight_seats = [0] * n
8
9 # Iterate through each booking to update flight_seats
10 for start, end, seats in bookings:
11 # Increase the seats count at the start index
12 flight_seats[start - 1] += seats
13
14 # Decrease the seats count at the index after the end to nullify the increase
15 # which will happen due to prefix sum (accumulate) later
16 if end < n:
17 flight_seats[end] -= seats
18
19 # Calculate the prefix sum which gives the total number of seats booked
20 # for each flight from the beginning
21 return list(accumulate(flight_seats))
22
1class Solution {
2
3 /*
4 This method calculates the number of seats booked on each flight.
5
6 Parameters:
7 bookings - an array of bookings, where bookings[i] = [first_i, last_i, seats_i]
8 n - the number of flights
9
10 Returns:
11 an array containing the total number of seats booked for each flight.
12 */
13 public int[] corpFlightBookings(int[][] bookings, int n) {
14 // Initialize an array to hold the answer, with n representing the number of flights.
15 int[] answer = new int[n];
16
17 // Iterate over each booking.
18 for (int[] booking : bookings) {
19 // Extract the start and end flight numbers and the number of seats booked.
20 int startFlight = booking[0];
21 int endFlight = booking[1];
22 int seats = booking[2];
23
24 // Increment the seats for the start flight by the number of seats booked.
25 answer[startFlight - 1] += seats;
26
27 // If the end flight is less than the number of flights,
28 // decrement the seats for the flight immediately after the end flight.
29 if (endFlight < n) {
30 answer[endFlight] -= seats;
31 }
32 }
33
34 // Iterate over the answer array, starting from the second element,
35 // and update each position with the cumulative sum of seats booked so far.
36 for (int i = 1; i < n; ++i) {
37 answer[i] += answer[i - 1];
38 }
39
40 // Return the populated answer array.
41 return answer;
42 }
43}
44
1class Solution {
2public:
3 // Function to calculate how many seats are booked on each flight
4 vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) {
5 vector<int> seatsBooked(n); // Array to store the final number of seats booked for each flight
6
7 // Loop over all the booking records
8 for (auto& booking : bookings) {
9 int startFlight = booking[0]; // Start flight number of the booking
10 int endFlight = booking[1]; // End flight number of the booking
11 int seats = booking[2]; // Number of seats to be booked in this range
12
13 // Increment the seats booked for the start flight by the number of seats booked
14 seatsBooked[startFlight - 1] += seats;
15
16 // If the booking ends before the last flight, decrement the seats booked
17 // for the first flight after the end flight. This will be used later for
18 // calculating cumulative sum.
19 if (endFlight < n) {
20 seatsBooked[endFlight] -= seats;
21 }
22 }
23
24 // Calculate the cumulative sum to get the actual number of seats booked for each flight
25 for (int i = 1; i < n; ++i) {
26 seatsBooked[i] += seatsBooked[i - 1];
27 }
28
29 // Return the final results
30 return seatsBooked;
31 }
32};
33
1/**
2 * This function takes a list of bookings and the total number of flights (n),
3 * and returns an array where each element represents the total number of seats
4 * booked on that flight.
5 *
6 * @param {number[][]} bookings - A list where each element is a booking in the
7 * form [first, last, seats] indicating a booking from flight `first` to flight
8 * `last` (inclusive) with `seats` being the number of seats booked.
9 * @param {number} n - The total number of flights.
10 * @return {number[]} - An array representing the total number of seats booked
11 * on each flight.
12 */
13const corpFlightBookings = (bookings: number[][], n: number): number[] => {
14 // Initialize answer array with n elements set to 0.
15 const answer: number[] = new Array(n).fill(0);
16
17 // Loop through each booking.
18 for (const [first, last, seats] of bookings) {
19 // Increment the seats for the first flight in the current booking range.
20 answer[first - 1] += seats;
21 // Decrement the seats for the flight just after the last flight in
22 // the current booking range, if it is within bounds.
23 if (last < n) {
24 answer[last] -= seats;
25 }
26 }
27
28 // Aggregate the booked seats information.
29 // Each flight's bookings include its own and also the cumulative bookings
30 // from the previous flight. This is because the seats booked in the flight ranges
31 // overlap and the initial range difference accounted for it.
32 for (let i = 1; i < n; ++i) {
33 answer[i] += answer[i - 1];
34 }
35
36 // Return the final aggregated information about flight bookings.
37 return answer;
38};
39
Time and Space Complexity
The time complexity of the provided code is composed of two parts: the iteration through the bookings
list and the accumulation of the values in the ans
array.
The iteration through the bookings
list happens once for each booking. For each booking, the code performs constant-time operations: an increment at the start position and a decrement at the end position. Therefore, if there are k
bookings, this part has a time complexity of O(k)
.
The accumulate
function is used to compute the prefix sums of the ans
array, which has n
elements. This operation is linear in the number of flights, so it has a time complexity of O(n)
.
Combining these two parts, the overall time complexity of the code is O(k + n)
, since we have to consider both the number of bookings and the number of flights.
The space complexity of the code is primarily determined by the storage used for the ans
array, which has n
elements. The accumulate
function returns an iterator in Python, so it does not add additional space complexity beyond what is used for the ans
array. Therefore, the space complexity of the provided code is O(n)
.
Learn more about how to find time and space complexity quickly using problem constraints.
What's the output of running the following function using input 56
?
1KEYBOARD = {
2 '2': 'abc',
3 '3': 'def',
4 '4': 'ghi',
5 '5': 'jkl',
6 '6': 'mno',
7 '7': 'pqrs',
8 '8': 'tuv',
9 '9': 'wxyz',
10}
11
12def letter_combinations_of_phone_number(digits):
13 def dfs(path, res):
14 if len(path) == len(digits):
15 res.append(''.join(path))
16 return
17
18 next_number = digits[len(path)]
19 for letter in KEYBOARD[next_number]:
20 path.append(letter)
21 dfs(path, res)
22 path.pop()
23
24 res = []
25 dfs([], res)
26 return res
27
1private static final Map<Character, char[]> KEYBOARD = Map.of(
2 '2', "abc".toCharArray(),
3 '3', "def".toCharArray(),
4 '4', "ghi".toCharArray(),
5 '5', "jkl".toCharArray(),
6 '6', "mno".toCharArray(),
7 '7', "pqrs".toCharArray(),
8 '8', "tuv".toCharArray(),
9 '9', "wxyz".toCharArray()
10);
11
12public static List<String> letterCombinationsOfPhoneNumber(String digits) {
13 List<String> res = new ArrayList<>();
14 dfs(new StringBuilder(), res, digits.toCharArray());
15 return res;
16}
17
18private static void dfs(StringBuilder path, List<String> res, char[] digits) {
19 if (path.length() == digits.length) {
20 res.add(path.toString());
21 return;
22 }
23 char next_digit = digits[path.length()];
24 for (char letter : KEYBOARD.get(next_digit)) {
25 path.append(letter);
26 dfs(path, res, digits);
27 path.deleteCharAt(path.length() - 1);
28 }
29}
30
1const KEYBOARD = {
2 '2': 'abc',
3 '3': 'def',
4 '4': 'ghi',
5 '5': 'jkl',
6 '6': 'mno',
7 '7': 'pqrs',
8 '8': 'tuv',
9 '9': 'wxyz',
10}
11
12function letter_combinations_of_phone_number(digits) {
13 let res = [];
14 dfs(digits, [], res);
15 return res;
16}
17
18function dfs(digits, path, res) {
19 if (path.length === digits.length) {
20 res.push(path.join(''));
21 return;
22 }
23 let next_number = digits.charAt(path.length);
24 for (let letter of KEYBOARD[next_number]) {
25 path.push(letter);
26 dfs(digits, path, res);
27 path.pop();
28 }
29}
30
Recommended Readings
Prefix Sum The prefix sum is an incredibly powerful and straightforward technique Its primary goal is to allow for constant time range sum queries on an array What is Prefix Sum The prefix sum of an array at index i is the sum of all numbers from index 0 to i By
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!