My Calendar II

Updated on 18 June, 2025
My Calendar II header image

Problem Statement

In the given task, you are to implement a calendar system that tracks the booking of time intervals using a class called MyCalendarTwo. The system allows the addition of new events, each specified by a start time and an end time, represented as a half-open interval [startTime, endTime). This interval includes the start time but excludes the end time, effectively covering moments where startTime <= x < endTime.

The core requirement of this system is preventing what is termed a "triple booking". A "triple booking" occurs when three distinct events overlap at any point in time. The class MyCalendarTwo should support the initialization of a calendar object and a method book(int startTime, int endTime), which attempts to add a new event to the calendar. If adding the new event results in any triple booking, the method should return false and reject the event. Otherwise, it should return true, indicating that the event has been successfully added without violations.

The implementation needs to cater efficiently to the possibility that up to 1000 events may need to be booked, with any potential start or end time ranging from 0 to 1,000,000,000.

Examples

Example 1

Input:

["MyCalendarTwo", "book", "book", "book", "book", "book", "book"]
[[], [10, 20], [50, 60], [10, 40], [5, 15], [5, 10], [25, 55]]

Output:

[null, true, true, true, false, true, true]

Explanation:

MyCalendarTwo myCalendarTwo = new MyCalendarTwo();
myCalendarTwo.book(10, 20); // return true
myCalendarTwo.book(50, 60); // return true
myCalendarTwo.book(10, 40); // return true (double booking)
myCalendarTwo.book(5, 15);  // return false (triple booking)
myCalendarTwo.book(5, 10);  // return true
myCalendarTwo.book(25, 55); // return true

Constraints

  • 0 <= start < end <= 10^9
  • At most 1000 calls will be made to book.

Approach and Intuition

To solve this problem effectively, we must ensure that we allow:

  • Single bookings: One event in a time range.
  • Double bookings: Two events overlapping in a time range.

But we must disallow:

  • Triple bookings: Three events overlapping in any time range.

Step-by-Step Strategy

  1. Track Booked Events:

    • Maintain a list booked of all successfully added intervals.
    • Maintain another list overlaps of all intervals that have been double booked.
  2. Check for Triple Booking:

    • For each new interval [start, end) to be booked:

      • First, check if it overlaps with any existing interval in overlaps. If it does, adding it would create a triple booking. Return false.
      • If not, proceed to step 3.
  3. Update Overlaps:

    • For each existing event in booked, check if it overlaps with the new event:

      • If there is an overlap, compute the intersection interval and add it to overlaps.
  4. Add to Booked List:

    • Once it's verified that no triple booking occurs, add the new interval to the booked list.

Example Walkthrough

  • Booking [10, 20]: No overlap exists yet → allowed.
  • Booking [10, 40]: Overlaps with [10, 20] → double booked on [10, 20].
  • Booking [5, 15]: Overlaps with [10, 20] and also [10, 40] → [10, 15] would be triple booked → reject.

Code-Level Insight

This solution is O(N²) in the worst case where each new event overlaps with many others, but it's acceptable for N <= 1000 as per the constraint.

It efficiently handles arbitrary time intervals in a large range (up to 1e9) without the need for segment trees or complex structures by directly managing overlapping intervals through linear comparisons. This keeps implementation clean and effective for the problem's limits.

Solutions

  • C++
  • Java
  • Python
cpp
class MyCalendarTwo {
public:
    map<int, int> bookings;
    int maxOverlap;

    MyCalendarTwo() { maxOverlap = 2; }

    bool book(int start, int end) {
        bookings[start]++;
        bookings[end]--;

        int currentOverlap = 0;
        for (auto const& booking : bookings) {
            currentOverlap += booking.second;

            if (currentOverlap > maxOverlap) {
                bookings[start]--;
                bookings[end]++;

                if (bookings[start] == 0) {
                    bookings.erase(start);
                }
                if (bookings[end] == 0) {
                    bookings.erase(end);
                }

                return false;
            }
        }

        return true;
    }
};

Address the "My Calendar II" problem using C++ by managing overlapping events with proper handling of intervals. The implementation utilizes a map<int, int> to track the start and end times of booked intervals and dynamically adjusts overlaps with each new booking attempt.

  • Define variables bookings to store event start (+1) and end (-1) times, and maxOverlap set at 2 for allowing double booking but not more. Initialize maxOverlap in the constructor.
  • Implement the book function to add or remove bookings:
    • Increment entry for start time and decrement for end time in bookings.
    • Traverse the map to recalculate the current number of overlapping bookings.
    • If overlap exceeds 2 at any time during the iteration, reset changes by decrementing start and incrementing end back, and handle any resultant zero-values by removing them from the map, then return false.
    • If no overlap constraint is violated, return true, indicating successful booking.

This approach efficiently checks and handles each event's possible overlap while maintaining a tally of ongoing bookings, allowing quick adjustments and validations for new events.

java
class CalendarScheduler {

    private TreeMap<Integer, Integer> eventBookings;
    private int maxSimultaneousEvents;

    public CalendarScheduler() {
        eventBookings = new TreeMap<>();
        maxSimultaneousEvents = 2;
    }

    public boolean book(int start, int end) {
        // Modify booking counts at start and end points
        eventBookings.put(start, eventBookings.getOrDefault(start, 0) + 1);
        eventBookings.put(end, eventBookings.getOrDefault(end, 0) - 1);

        int currentOverlap = 0;

        // Calculate current overlaps
        for (Map.Entry<Integer, Integer> entry : eventBookings.entrySet()) {
            currentOverlap += entry.getValue();

            // Check if current overlap exceeds the threshold
            if (currentOverlap > maxSimultaneousEvents) {
                // Undo the booking
                eventBookings.put(start, eventBookings.get(start) - 1);
                eventBookings.put(end, eventBookings.get(end) + 1);

                // Remove the entry if no bookings exist
                if (eventBookings.get(start) == 0) {
                    eventBookings.remove(start);
                }
                
                return false;
            }
        }

        return true;
    }
}

The My Calendar II problem is tackled here using a Java implementation that manages a scheduling system allowing the booking of events. Here’s a breakdown of how this solution approaches it:

  • A TreeMap named eventBookings is utilized to keep track of the number of ongoing events at any given time.
  • The system uses this TreeMap to record changes at the start and the end of an event. When an event starts, it increments the count at the starting time, and when it ends, it decrements the count at the ending time.
  • The booking method checks if adding a new event would cause the number of simultaneous events to exceed two (set by maxSimultaneousEvents).
  • As each event is booked, the method iterates through all booked times in eventBookings. Cumulative overlaps are calculated by summing the values (increments and decrements).
  • If at any point the cumulative number of events exceeds the maximum allowed simultaneous events, the current booking is reversed. The event count is adjusted to its previous state both at the start and at the end times, ensuring the system maintains consistency.
  • If no events exist for a particular start time after a rollback, that time key is removed from the map to keep the system clean.
  • The function returns true if the booking is successful without exceeding the simultaneous event limit, otherwise, it returns false.

This Java solution effectively manages event bookings by keeping a dynamic count of start and end points while ensuring that the overlap does not exceed a defined threshold, providing a robust model for handling concurrent event bookings efficiently.

python
from sortedcontainers import SortedDict

class CalendarScheduler:

    def __init__(self):
        # Key schedule data.
        self.schedule_tracker = SortedDict()
        # Set the maximum allowed simultaneous events.
        self.allowed_overlap = 2

    def reserve(self, begin: int, conclusion: int) -> bool:
        # Manage scheduling tracking.
        self.schedule_tracker[begin] = self.schedule_tracker.get(begin, 0) + 1
        self.schedule_tracker[conclusion] = self.schedule_tracker.get(conclusion, 0) - 1

        current_overlap = 0

        # Evaluate ongoing events.
        for occurrence in self.schedule_tracker.values():
            current_overlap += occurrence
            # Check if the overlap exceeds permissible limits.
            if current_overlap > self.allowed_overlap:
                # Undo the reservation.
                self.schedule_tracker[begin] -= 1
                self.schedule_tracker[conclusion] += 1

                # Cleanup zero entries.
                if self.schedule_tracker[begin] == 0:
                    del self.schedule_tracker[begin]

                return False

        return True

The given Python code introduces a class, CalendarScheduler, utilizing the SortedDict from the sortedcontainers module to manage appointment reservations. This class supports checking if a new event can be added to the calendar without causing unacceptable overlaps greater than two concurrent events. Here is a concise breakdown of how the solution works:

  • Initialization:

    • An instance of SortedDict is created to track the start and end of calendar events.
    • The allowed_overlap property is set to limit the number of overlapping events to two.
  • Reservation Process:

    • The reserve method adjusts entries in schedule_tracker to increase the count at the start time of the event and decrease it at the end time.
    • It calculates ongoing overlaps by iterating through the values of schedule_tracker.
    • If the overlap exceeds the threshold (allowed_overlap), the insertion process reverses, decrementing and incrementing at the start and end times, respectively. It further cleans up the tracker by removing entries that drop to zero.
  • Event Addition Outcome:

    • Returns True if the event addition stays within the permissible overlap limit.
    • Returns False if adding the event would exceed the limit, ensuring no changes disrupt the existing schedule state.

This mechanism effectively manages a calendar with constraints on event overlaps, ensuring a user-friendly approach to scheduling.

Comments

No comments yet.