Skip to main content

Corporate Flight Bookings Range Updates Problem

Solution to the corporate flight bookings problem using range update techniques and difference arrays for efficient batch updates.

The corporate flight bookings problem requires efficiently processing batch updates to flight seat allocations across ranges of flights, which can be solved optimally using difference array techniques for O(1) range updates.

1. Problem Restatement

Clarifying questions to ask the interviewer:

  1. What is the maximum size of the flights array and booking ranges? (e.g., up to 10^5 or 10^6?)
  2. Are there any constraints on the booking ranges (e.g., start ≤ end, all positive integers)?
  3. Should we return a new array or mutate the input?
  4. Can we assume that all flight numbers are within [1, n] where n is the number of flights?
  5. What should we return if there are no bookings or if the input is empty?

Restatement in my own words: We are given a list of flight bookings where each booking specifies a range of flights and the number of seats reserved for each flight in that range. The task is to compute the total number of seats reserved for each individual flight across all bookings.

Problem details:

  • Input: A 2D array bookings where each element is [first, last, seats] indicating that seats number of seats are reserved for all flights from first to last (inclusive)
  • Output: An array of size n where n is the total number of flights, with each element representing the total seats reserved for that flight
  • Constraints:
    • 1 ≤ n ≤ 2 * 10^4
    • 1 ≤ bookings.length ≤ 10^5
    • 1 ≤ first ≤ last ≤ n
    • 1 ≤ seats ≤ 10^4

Assumptions I'm making:

  • Flight numbers are 1-indexed (as is typical in such problems)
  • The input array bookings can be mutated if needed (though we'll use an approach that doesn't require mutation)
  • All flights are within the valid range [1, n]
  • The result array should be 0-indexed (but we'll handle the 1-indexing mapping cleanly)

Data shape and hidden structure: The problem exhibits a classic "range update" pattern where we're applying multiple range-based updates to an array. The key insight is that instead of updating each element in a range individually, we can use a difference array technique to make the updates more efficient.

The structure is that we're dealing with overlapping intervals (ranges) that need to be merged or accumulated, which suggests either a sweep line algorithm or difference array approach.

2. Pattern Recognition

Identifying the pattern

This problem exhibits the range update pattern or difference array pattern. The key signal words are "bookings" and "flights" which indicate that we're dealing with ranges of updates to be applied to a sequence.

Why this fits the pattern

The problem asks us to process multiple range updates efficiently. Each booking specifies a start and end flight number (inclusive) and an increment value to apply to all flights in that range. This is a classic example of the difference array technique where we want to apply multiple range updates and then compute the final result.

Core insight

The key insight is that instead of updating every element in each range directly (which would be O(n²)), we can use a difference array approach where:

  1. We mark the start of each range with +value and end+1 with -value
  2. Then compute prefix sums to get the actual values

This transforms range updates from O(n) each to O(1) each, making the overall complexity O(n + m) where n is flight count and m is booking count.

Pattern characteristics

  • Range operations: Multiple updates to ranges of elements
  • Efficient range updates: Need to avoid O(n²) brute force
  • Final aggregation: Need to compute actual values from difference markers
  • In-place processing: Can process updates without storing full arrays initially

This is a well-known pattern that appears in problems like "Meeting Rooms II", "Car Pooling", and various interval scheduling problems.

3. Approach Evolution

Interview communication script:

My first instinct is to use a brute force approach where I iterate through each booking and increment the seat count for every flight in that range. But that's O(n × m) where n is the number of flights and m is the number of bookings, which could be very inefficient. Let me think about how to optimize this.

I notice that if I maintain the difference array invariant, I can reduce it to O(n + m) by using a sweep line technique. The key insight is that instead of updating every element in a range, I can mark the start and end points of each update.

Let me think about this more systematically. If I have a range update from index start to end with value val, instead of adding val to each position in that range, I can add val at position start and subtract val at position end + 1. Then I can compute prefix sums to get the actual values.

This approach is much more efficient because:

  1. Each booking update becomes O(1) operation
  2. Final computation is O(n)
  3. Total complexity becomes O(n + m) instead of O(n × m)

The core insight is that we're dealing with a range update problem that can be efficiently solved using the difference array technique, which is a classic pattern for handling multiple range updates.

Brute-force approach: The naive solution would iterate through each booking and for every flight in the range [start, end], increment its seat count by the booking's value. This would require O(n × m) time where n is the number of flights and m is the number of bookings. For large inputs, this becomes prohibitively expensive.

Improved approach: I'll use the difference array technique. Instead of updating ranges directly, I'll mark the beginning and end of each range update:

  1. For booking [start, end, value], I add value to difference[start]
  2. I subtract value from difference[end + 1]
  3. Finally, compute prefix sums to get actual seat counts

Final approach with step-by-step reasoning:

  1. Create a difference array of size n + 1 (extra space to handle boundary conditions)
  2. For each booking [start, end, value]:
    • Add value to difference[start]
    • Subtract value from difference[end + 1]
  3. Compute prefix sums to convert difference array back to actual seat counts
  4. Return first n elements (excluding the extra element)

Important invariants that must hold:

  • Difference array size must be n + 1 to avoid index out of bounds when accessing end + 1
  • Range updates must be applied at correct indices: start and end + 1
  • Prefix sum computation must start from index 1 to properly accumulate changes

4. Data Structure Choice

For this range update problem, I'll use a difference array approach as the primary data structure.

The difference array is ideal because:

  1. It allows efficient range updates in O(1) time
  2. It can be converted back to the actual array in O(n) time
  3. It's a well-known pattern for range update queries

The key insight is that instead of updating every element in a range directly, we mark the start and end points of updates:

  • For an update [start, end] with value delta, we add delta at index start and subtract delta at index end + 1
  • Then we compute prefix sums to get the actual values

Why this approach:

  • Time complexity: O(n + m) where n is the number of flights and m is the number of bookings
  • Space complexity: O(n) for the difference array
  • The approach is optimal for this specific problem type

Helper structures:

  • Integer array of size n + 1 to handle the difference array (extra space to avoid boundary checks)
  • No additional data structures needed beyond this

This choice enables the cleanest implementation of the sweep line technique and provides optimal performance for range updates. The difference array pattern is commonly tested in FAANG interviews as it demonstrates understanding of efficient range operations and prefix sum techniques.

The approach elegantly handles the constraint that we're doing multiple range updates efficiently, which is a classic application of difference arrays.

5. Algorithm Walkthrough

Let me trace through the algorithm with a concrete example to show how it works step by step.

Example: bookings = [[1,2,10], [2,3,20], [2,4,25]], n = 4

Step 1: Initialize the result array

bookings = [[1,2,10], [2,3,20], [2,4,25]]
n = 4
result = [0, 0, 0, 0]

Step 2: Process each booking interval

  • Booking [1,2,10]: Add 10 to index 0 (start), subtract 10 from index 2 (end+1)
result = [10, 0, -10, 0]

Step 3: Process second booking [2,3,20]

  • Add 20 to index 1 (start), subtract 20 from index 3 (end+1)
result = [10, 20, -10, -20]

Step 4: Process third booking [2,4,25]

  • Add 25 to index 1 (start), subtract 25 from index 4 (end+1) - but index 4 doesn't exist, so we skip
result = [10, 45, -10, -20]

Step 5: Compute prefix sum to get actual passenger counts

i=0: result[0] = 10
i=1: result[1] = 10 + 45 = 55
i=2: result[2] = 55 + (-10) = 45
i=3: result[3] = 45 + (-20) = 25

Final result: [10, 55, 45, 25]

Key insights in this walkthrough:

  • The difference array technique allows us to mark range updates in O(1) time
  • We only need to update two positions per booking: start and end+1
  • The prefix sum operation converts the difference array back to actual values
  • This approach handles overlapping ranges correctly by accumulating the deltas

Edge case handling:

  • When end+1 exceeds array bounds, we simply don't update that position
  • The prefix sum ensures all positions are properly calculated regardless of how many bookings overlap at any point

6. Java Solution

public class Solution {
    public int[] corpFlightBookings(int[][] bookings, int n) {
        // Initialize difference array with size n+1 to handle range updates easily
        int[] diff = new int[n + 1];
        
        // Process each booking to mark the range updates
        for (int[] booking : bookings) {
            int first = booking[0];     // Starting flight index (1-indexed)
            int last = booking[1];      // Ending flight index (1-indexed)
            int seats = booking[2];     // Number of seats to add to each flight in range
            
            // Apply difference array technique:
            // Add seats at the start of range
            diff[first - 1] += seats;
            // Subtract seats just after the end of range
            diff[last] -= seats;
        }
        
        // Convert difference array back to actual seat counts
        int[] result = new int[n];
        result[0] = diff[0];
        for (int i = 1; i < n; i++) {
            result[i] = result[i - 1] + diff[i];
        }
        
        return result;
    }
}

This solution uses the difference array technique to efficiently handle range updates. For each booking, we mark the start and end of the range using the difference array approach, then convert it back to actual seat counts. The key insight is that we only need to update the boundaries of each range rather than updating every element in between.

7. Complexity Analysis

Time Complexity: O(n + m) where n is the number of flights and m is the number of booking ranges.

The solution processes each booking range exactly once in O(1) time using the difference array technique, and then performs a single linear scan to compute the final result array. Since we iterate through the bookings once and then once more through the result array, the total time complexity is linear in the sum of input sizes.

Space Complexity: O(n) where n is the number of flights.

We use a difference array of size n+1 to store the range updates, and an additional result array of size n to return the final answer. The extra space is linear in the number of flights, which is the primary driver of space usage.

Why these bounds are correct:

The difference array approach ensures that each booking operation takes constant time O(1) by only updating the start and end+1 positions. The final prefix sum computation is O(n) since we iterate through all n elements once to convert the difference array back to actual values.

The solution is optimal because:

  1. We must read all m booking ranges at least once to process them
  2. We must produce n output values at least once to return the answer
  3. No better algorithm exists for this problem that avoids reading all inputs at least once

The solution achieves the theoretical lower bound of O(n + m) for this class of range update problems, making it near-optimal for the given constraints.

// Time: O(n + m) where n = flights, m = bookings
// Space: O(n) for difference array and result

8. Edge Cases & Pitkins

Edge cases and pitfalls that candidates should consider:

Empty Input: When bookings is empty or has zero length, the result should be an array of zeros with size n. The solution must handle this gracefully without index out of bounds errors.

Single booking: When there's only one booking, the algorithm should correctly apply the range update to the appropriate indices.

Overlapping ranges: Multiple bookings may have overlapping ranges, which means we need to properly accumulate the seat counts. The solution must correctly sum contributions from multiple bookings affecting the same range.

Boundary conditions:

  • Bookings that start at index 0 or end at index n-1
  • Bookings that span the entire range [1, n]
  • Bookings with same start and end positions (single seat updates)

Integer overflow: While the problem constraints state that bookings[i][2] is at most 10^4 and there are at most 10^4 bookings, the cumulative sum could theoretically exceed Integer.MAX_VALUE. However, with the given constraints (n ≤ 2 * 10^4), this is not an issue in practice.

Indexing confusion: The problem uses 1-based indexing for flight numbers but Java arrays use 0-based indexing. The solution must correctly map between these systems (booking start/end indices are 1-based, but array access is 0-based).

Array bounds: When applying range updates using difference array technique, we must ensure that start - 1 and end indices don't go out of bounds. Specifically, start - 1 should be ≥ 0 and end should be ≤ n.

Common implementation mistakes include:

  1. Forgetting to convert from 1-based booking indices to 0-based array indices
  2. Incorrectly handling the end boundary in difference array updates (should be end not end - 1)
  3. Not properly initializing the result array to zeros
  4. Using incorrect loop bounds when computing prefix sums

9. Alternative Approaches

There are several alternative approaches to solving the corporate flight bookings problem, each with different trade-offs:

1. Segment Tree Approach

  • Use a segment tree with lazy propagation for range updates
  • Time complexity: O(n log n) for updates + O(log n) per query
  • Space complexity: O(n)
  • This is overkill for this problem since we don't need frequent queries, but it's a valid approach for more complex range update scenarios

2. Binary Indexed Tree (Fenwick Tree) Approach

  • Similar to segment tree but more space-efficient
  • Time complexity: O(log n) per range update and query
  • Space complexity: O(n)
  • More complex to implement correctly for range updates compared to the difference array approach

3. Simple Brute Force with HashMap

  • For each booking, iterate through all flights and update the count
  • Time complexity: O(n × k) where k is average booking length, worst case O(n²)
  • Space complexity: O(1) additional space
  • This is inefficient but works for small inputs and demonstrates understanding of the problem

4. Sorting + Sweep Line

  • Sort all booking start/end events and process them in order
  • Time complexity: O(n log n) due to sorting
  • Space complexity: O(n)
  • This approach is more complex and less intuitive than the difference array method

The difference array approach is preferred because it's simpler to implement correctly, more intuitive, and achieves optimal O(n) time complexity. The alternatives are more complex to implement and don't provide significant advantages for this specific problem structure.

The key insight is that we're not just doing point updates, but range updates that can be efficiently converted to difference array operations. This makes the difference array approach the most elegant and efficient solution for this particular problem pattern.

10. Test Cases

public class FlightBookingTests {
    
    @Test
    public void testBasicExample() {
        // Input: bookings = [[1,2,10],[2,3,20],[3,4,30]], n = 4
        // Expected: [10, 50, 80, 30]
        int[][] bookings = {{1,2,10},{2,3,20},{3,4,30}};
        int n = 4;
        int[] expected = {10, 50, 80, 30};
        assertArrayEquals(expected, corpFlightBookings(bookings, n));
    }
    
    @Test
    public void testSingleBooking() {
        // Input: bookings = [[1,4,10]], n = 4
        // Expected: [10, 10, 10, 10]
        int[][] bookings = {{1,4,10}};
        int n = 4;
        int[] expected = {10, 10, 10, 10};
        assertArrayEquals(expected, corpFlightBookings(bookings, n));
    }
    
    @Test
    public void testOverlappingBookings() {
        // Input: bookings = [[1,3,10],[2,4,20],[3,5,30]], n = 5
        // Expected: [10, 30, 60, 50, 30]
        int[][] bookings = {{1,3,10},{2,4,20},{3,5,30}};
        int n = 5;
        int[] expected = {10, 30, 60, 50, 30};
        assertArrayEquals(expected, corpFlightBookings(bookings, n));
    }
    
    @Test
    public void testEmptyInput() {
        // Input: bookings = [], n = 3
        // Expected: [0, 0, 0]
        int[][] bookings = {};
        int n = 3;
        int[] expected = {0, 0, 0};
        assertArrayEquals(expected, corpFlightBookings(bookings, n));
    }
    
    @Test
    public void testSingleFlight() {
        // Input: bookings = [[1,1,100]], n = 1
        // Expected: [100]
        int[][] bookings = {{1,1,100}};
        int n = 1;
        int[] expected = {100};
        assertArrayEquals(expected, corpFlightBookings(bookings, n));
    }
    
    @Test
    public void testLargeRange() {
        // Input: bookings = [[1,n,100]], n = 1000
        // Expected: [1000, 1000, ..., 1000] (all 1000s)
        int n = 1000;
        int[][] bookings = {{1, n, 100}};
        int[] expected = new int[n];
        Arrays.fill(expected, 100);
        assertArrayEquals(expected, corpFlightBookings(bookings, n));
    }
}

11. Final Summary

The core insight is to use a difference array technique to efficiently apply range updates and then compute the final result through prefix sums. This approach transforms the problem from O(n×k) to O(n+k) where n is the number of flights and k is the number of bookings, making it optimal for large inputs. The solution works by marking the start and end of each booking range, then computing cumulative sums to get the actual passenger counts for each flight. The key efficiency comes from avoiding redundant updates to individual flight seats and instead processing all range updates in a single pass followed by a simple cumulative computation.

Was this article helpful?

Topics in this article

More from DSA Problems

  • DSA Patterns

    Subsets and Permutations Problem Solving Patterns in Java

    Comprehensive guide to subset and permutation generation algorithms with iterative and recursive approaches, including time complexity analysis and practical implementation strategies.

  • DSA Problems

    Max Area of Island Java Solution

    Complete Java implementation for finding maximum area of island in 2D grid using DFS and BFS approaches with time and space complexity analysis.

  • DSA Problems

    Rotting Oranges Java Solution with BFS

    Complete Java implementation of the rotting oranges problem using breadth-first search to find minimum time for all oranges to rot.

Stay in the Loop

Get curated DSA patterns, coding problems, frontend and backend LLD/HLD, and AI/ML System Design insights delivered straight to your inbox. No spam, just focused interview and engineering content.