{x}
blog image

My Calendar I

You are implementing a program to use as your calendar. We can add a new event if adding the event will not cause a double booking.

A double booking happens when two events have some non-empty intersection (i.e., some moment is common to both events.).

The event can be represented as a pair of integers startTime and endTime that represents a booking on the half-open interval [startTime, endTime), the range of real numbers x such that startTime <= x < endTime.

Implement the MyCalendar class:

  • MyCalendar() Initializes the calendar object.
  • boolean book(int startTime, int endTime) Returns true if the event can be added to the calendar successfully without causing a double booking. Otherwise, return false and do not add the event to the calendar.

 

Example 1:

Input
["MyCalendar", "book", "book", "book"]
[[], [10, 20], [15, 25], [20, 30]]
Output
[null, true, false, true]

Explanation
MyCalendar myCalendar = new MyCalendar();
myCalendar.book(10, 20); // return True
myCalendar.book(15, 25); // return False, It can not be booked because time 15 is already booked by another event.
myCalendar.book(20, 30); // return True, The event can be booked, as the first event takes every time less than 20, but not including 20.

 

Constraints:

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

Solution Explanation: My Calendar I

This problem asks to design a calendar system that allows booking events, but prevents double bookings. A double booking occurs when two events overlap in time. The solution uses an ordered set (or a similar data structure like a sorted map) to efficiently check for overlaps and book events.

Approach: Using an Ordered Set (TreeMap in Java, SortedDict in Python, etc.)

The core idea is to maintain a sorted collection of booked events. Each event is represented by its endTime. The startTime is implicitly stored, and we exploit the sorted nature of the data structure for efficient overlap checking.

  1. Data Structure: We utilize an ordered set (like TreeMap in Java, SortedDict in Python, or std::map in C++). This structure automatically keeps entries sorted by keys (endTime in this case).

  2. book(startTime, endTime) Function:

    a. Binary Search (Implicit): The book function implicitly performs a binary search to locate the position where the new event's endTime should be inserted. Methods like bisect_right in Python's SortedDict or ceilingEntry in Java's TreeMap directly provide this functionality.

    b. Overlap Check: After finding the correct position, we check for overlaps. We examine the event immediately after the insertion position (if one exists). An overlap occurs if:

    • There's a next event (nextEvent), and
    • The nextEvent's startTime is less than the new event's endTime.

    c. Booking: If no overlap is detected, we insert the new event (using its endTime as the key and startTime as the value in the map) into the ordered set and return true. Otherwise, we return false.

Time and Space Complexity Analysis

  • Time Complexity: The dominant operation is the insertion and search within the ordered set. Ordered sets provide logarithmic time complexity for these operations: O(log n), where n is the number of booked events. Therefore, the overall time complexity of the book function is O(log n).

  • Space Complexity: The space used is proportional to the number of booked events stored in the ordered set. The space complexity is O(n).

Code Examples (Python and Java)

Python:

from sortedcontainers import SortedDict
 
class MyCalendar:
    def __init__(self):
        self.calendar = SortedDict()  # Sorted dictionary to store events
 
    def book(self, start: int, end: int) -> bool:
        idx = self.calendar.bisect_right(start) #Finds insertion point
        if idx < len(self.calendar) and self.calendar.values()[idx] < end:
            return False  # Overlap detected
        self.calendar[end] = start  # Book the event
        return True

Java:

import java.util.TreeMap;
 
class MyCalendar {
    private TreeMap<Integer, Integer> calendar;
 
    public MyCalendar() {
        calendar = new TreeMap<>();
    }
 
    public boolean book(int startTime, int endTime) {
        Map.Entry<Integer, Integer> entry = calendar.ceilingEntry(startTime + 1); //Finds next event
        if (entry != null && entry.getValue() < endTime) {
            return false; // Overlap
        }
        calendar.put(endTime, startTime); // Book the event
        return true;
    }
}

Other language examples (C++, Go, TypeScript, Rust, JavaScript) in the original response demonstrate the same core approach, adapted to their respective data structures and syntax. The underlying algorithm remains consistent across all implementations.