Implement and extend My Calendar III
Company: Pinterest
Role: Data Scientist
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates competency in designing and implementing efficient dynamic interval data structures, handling correctness for duplicate and nested intervals, extending APIs with cancellation and point queries, and performing rigorous worst-case time/space analysis and resource-adaptation.
Part 1: My Calendar III - Maximum Concurrent Bookings After Each Insert
Constraints
- `0 <= len(bookings) <= 100000`
- `0 <= start < end <= 10^9`
- Use half-open intervals: `[start, end)`
Examples
Input: [[10, 20], [50, 60], [10, 40], [5, 15], [5, 10], [25, 55]]
Expected Output: [1, 1, 2, 3, 3, 3]
Explanation: Standard My Calendar III example. The peak overlap becomes 3 after booking `[5, 15)`.
Input: [[10, 20], [20, 30], [15, 25]]
Expected Output: [1, 1, 2]
Explanation: Because intervals are half-open, `[10, 20)` and `[20, 30)` do not overlap at time 20.
Hints
- Compress all distinct start and end coordinates first. Each leaf can represent one elementary segment between consecutive coordinates.
- A booking `[s, e)` adds `+1` to every compressed segment from `index[s]` through `index[e] - 1`.
Part 2: Calendar Overlap with Half-Open Boundaries, Duplicates, and Nested Intervals
Constraints
- `0 <= len(intervals) <= 100000`
- `0 <= start < end <= 10^9`
- Intervals are half-open: `[start, end)`
Examples
Input: [[10, 20], [20, 30], [15, 25]]
Expected Output: 2
Explanation: Touching intervals do not overlap at 20, but `[15, 25)` overlaps with each of the other two on different subranges.
Input: [[10, 20], [10, 20], [10, 20]]
Expected Output: 3
Explanation: Duplicate intervals all count separately.
Hints
- A difference map works well: add `+1` at each start and `-1` at each end, then sweep from left to right.
- With half-open intervals, events at the same coordinate can cancel out naturally in the difference map.
Part 3: Extended Calendar with book, cancel, and query
Constraints
- `0 <= len(operations) <= 100000`
- `0 <= start < end <= 10^9`
- `0 <= t <= 10^9`
- Every `cancel(start, end)` refers to an interval that is currently booked at least once
- Intervals are half-open: `[start, end)`
Examples
Input: [['book', '10', '20'], ['book', '15', '25'], ['query', '10'], ['query', '20'], ['cancel', '10', '20'], ['query', '15'], ['book', '20', '30']]
Expected Output: [1, 2, 1, 1, 1, 1, 2]
Explanation: Shows both half-open behavior and that cancel correctly updates future max values and point queries.
Input: [['book', '5', '10'], ['book', '5', '10'], ['query', '7'], ['cancel', '5', '10'], ['query', '7'], ['cancel', '5', '10'], ['query', '7']]
Expected Output: [1, 2, 2, 1, 1, 0, 0]
Explanation: Duplicate bookings are tracked independently, and cancel removes one copy at a time.
Hints
- Use the same compressed elementary segments as in My Calendar III, but allow both `+1` and `-1` range updates.
- For `query(t)`, find which compressed segment contains `t`, then read the point value on that segment.
Part 4: Non-Recursive My Calendar III for Adversarial Inputs
Constraints
- `0 <= len(bookings) <= 100000`
- `0 <= start < end <= 10^9`
- Intervals are half-open: `[start, end)`
- Use a non-recursive approach for the segment tree updates
Examples
Input: [[10, 20], [50, 60], [10, 40], [5, 15], [5, 10], [25, 55]]
Expected Output: [1, 1, 2, 3, 3, 3]
Explanation: Same benchmark sequence as the classic problem.
Input: [[0, 1000000000], [0, 1000000000], [0, 1000000000], [0, 1000000000]]
Expected Output: [1, 2, 3, 4]
Explanation: Adversarial-style heavy overlap: every interval covers the full range.
Hints
- Coordinate compression still turns huge times into a compact index range over elementary segments.
- In an iterative lazy segment tree, after applying updates to cover nodes, rebuild only the ancestors of the touched boundary leaves.