~/problems / Intervals

The first gap everyone shares

easy ~20 min Citadel

You're writing the "find a time" button of a calendar app. The input is a log of calendar edits, events, in the order they were made. Each is a string

"<name> <action> <start> <end>"      e.g. "maya busy 09:00 10:29"
  • <name> is a person (no spaces, case-sensitive). Everyone who appears in the log, with either action, must attend.
  • <start> and <end> are "HH:MM" times on one day ("00:00" to "23:59"), with start <= end. The range covers every minute from start through end, both included: "09:00 10:29" is the 90 minutes 09:00, 09:01, ..., 10:29.
  • <action> is busy (mark those minutes as busy for that person) or free (mark them free again, e.g. a cancelled meeting). Later edits override earlier ones for the minutes they cover.

Implement

earliest_slot(events: list[str], k: int) -> str | None

returning the start ("HH:MM") of the earliest run of k consecutive minutes (k >= 1) that are free for every person and lie entirely within the day (the last usable minute is 23:59), or None if there is none.

events = [
    "maya busy 09:00 10:29",
    "raj busy 10:45 11:59",
    "maya busy 00:00 08:59",
    "raj free 11:00 11:59",
]
earliest_slot(events, 15)    # "10:30"   (10:30-10:44 is free for both)
earliest_slot(events, 16)    # "11:00"   (raj freed 11:00-11:59)
earliest_slot(["ana busy 00:00 23:58"], 1)   # "23:59"
earliest_slot(["ana busy 00:00 23:58"], 2)   # None
earliest_slot([], 1440)      # "00:00"

Constraints: up to 2,000 events, 1 <= k <= 10**6 (a k above 1440 can never fit).

Show hint

The day only has 1440 minutes. Keep one boolean array per person, apply the edits in order, then combine: a minute is usable if no one is busy in it. Scan the day once, counting the length of the current run of usable minutes.

Topic: Intervals / sweep line. Sort by start, merge; sweep events for overlaps.

Read the visual guide
0:00
Ctrl ' run · Ctrl ↵ submit
esc