PracHub
QuestionsPremiumLearningGuidesCheatsheetNEWCoaches

Quick Overview

This question evaluates proficiency with interval manipulation, timeline merging, and algorithmic reasoning for scheduling constraints, measuring competency in handling sorted interval lists, edge-case sanitization, and complexity analysis.

  • Medium
  • Citadel
  • Coding & Algorithms
  • Software Engineer

Find earliest common meeting slot

Company: Citadel

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: Medium

Interview Round: Technical Screen

Given K participants' calendars, each a list of busy intervals [start, end) within a working window [workStart, workEnd], and a meeting duration d minutes, return the earliest interval [t, t + d) that is within every participant's working window and does not overlap any busy interval. Times are integers in minutes from 00:00. Busy intervals are non-overlapping and sorted within each calendar. If no slot exists, return an empty list. Design an algorithm, state its time and space complexity, and describe how you would handle unsorted or overlapping inputs and large K efficiently.

Quick Answer: This question evaluates proficiency with interval manipulation, timeline merging, and algorithmic reasoning for scheduling constraints, measuring competency in handling sorted interval lists, edge-case sanitization, and complexity analysis.

You are given K participants. calendars[i] is a list of busy half-open intervals [start, end) in minutes from 00:00, and work_windows[i] = [workStart, workEnd] represents that participant's available working window, interpreted as [workStart, workEnd). Given an integer d, return the earliest half-open interval [t, t + d) that lies inside every participant's working window and does not overlap any busy interval from any participant. Return the answer as [t, t + d]. If no such slot exists, return []. For the core problem, calendars are intended to be sorted and non-overlapping. As a follow-up, explain how you would normalize unsorted or overlapping calendars first, and how to stay efficient when K is large.

Constraints

  • 1 <= len(calendars) == len(work_windows) <= 100000
  • 0 <= total number of busy intervals across all calendars <= 200000
  • 0 <= start < end <= 1440
  • 0 <= workStart < workEnd <= 1440
  • 1 <= d <= 1440

Examples

Input: ([[[540, 570], [630, 660]], [[555, 585], [615, 645]], [[600, 615]]], [[480, 720], [540, 690], [510, 660]], 15)

Expected Output: [585, 600]

Explanation: The common working window is [540, 660). After merging busy times across all three calendars, the first free gap of length 15 is [585, 600).

Input: ([[[540, 600], [620, 660]], [[530, 610]], [[600, 650]]], [[540, 660], [540, 660], [540, 660]], 10)

Expected Output: []

Explanation: All busy intervals merge to cover the entire common working window [540, 660), so no 10-minute slot exists.

Input: ([[[100, 130], [90, 110], [150, 160]], [[80, 95], [125, 140]]], [[80, 170], [70, 170]], 10)

Expected Output: [140, 150]

Explanation: Normalize the first calendar to [90, 130) and [150, 160). After merging both participants' busy times, the first 10-minute gap is [140, 150).

Input: ([[], []], [[480, 540], [500, 560]], 20)

Expected Output: [500, 520]

Explanation: The common working window is [500, 540) and nobody is busy, so the earliest 20-minute slot starts at 500.

Input: ([[], []], [[100, 120], [130, 150]], 5)

Expected Output: []

Explanation: The participants' working windows do not overlap, so there is no common time to meet.

Input: ([[[10, 20], [20, 30]], [[0, 15], [35, 40]]], [[0, 50], [0, 50]], 5)

Expected Output: [30, 35]

Explanation: Adjacent busy intervals [10, 20) and [20, 30) leave no free gap at 20. After merging all busy time, the first 5-minute gap is [30, 35).

Solution

def solution(calendars, work_windows, d):
    import heapq

    if not calendars or not work_windows or len(calendars) != len(work_windows):
        return []

    common_start = max(window[0] for window in work_windows)
    common_end = min(window[1] for window in work_windows)

    if common_end - common_start < d:
        return []

    def normalize(calendar):
        intervals = []
        for interval in calendar:
            if len(interval) != 2:
                continue
            start, end = interval
            if end <= start:
                continue
            intervals.append((start, end))

        intervals.sort()

        merged = []
        for start, end in intervals:
            if not merged or start > merged[-1][1]:
                merged.append([start, end])
            elif end > merged[-1][1]:
                merged[-1][1] = end

        clipped = []
        for start, end in merged:
            start = max(start, common_start)
            end = min(end, common_end)
            if start < end:
                clipped.append([start, end])

        return clipped

    normalized = [normalize(calendar) for calendar in calendars]

    heap = []
    for person, calendar in enumerate(normalized):
        if calendar:
            start, end = calendar[0]
            heapq.heappush(heap, (start, end, person, 0))

    if not heap:
        return [common_start, common_start + d]

    current = common_start

    while heap:
        start, end, person, idx = heapq.heappop(heap)

        next_idx = idx + 1
        if next_idx < len(normalized[person]):
            next_start, next_end = normalized[person][next_idx]
            heapq.heappush(heap, (next_start, next_end, person, next_idx))

        if end <= current:
            continue

        if start - current >= d:
            return [current, current + d]

        current = max(current, end)

        while heap and heap[0][0] <= current:
            start2, end2, person2, idx2 = heapq.heappop(heap)

            next_idx2 = idx2 + 1
            if next_idx2 < len(normalized[person2]):
                next_start2, next_end2 = normalized[person2][next_idx2]
                heapq.heappush(heap, (next_start2, next_end2, person2, next_idx2))

            if end2 > current:
                current = end2

    if common_end - current >= d:
        return [current, current + d]

    return []

Time complexity: O(sum(m_i log m_i) + M log K), where m_i is the size of calendar i and M is the total number of busy intervals after preprocessing. If calendars are already sorted and non-overlapping, preprocessing drops to O(M).. Space complexity: O(M + K).

Hints

  1. Any valid meeting must lie inside the intersection of all participants' working windows.
  2. After clipping busy intervals to that common window, treat each calendar as a sorted stream and merge the K streams with a min-heap instead of flattening everything when K is large.
Last updated: May 5, 2026

Loading coding console...

PracHub

Master your tech interviews with 7,500+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Implement a single-producer multi-consumer ring buffer - Citadel (medium)
  • Sort a Nearly Sorted Array - Citadel (hard)
  • Compute BBO and NBBO from order data - Citadel (medium)
  • Design dynamic weighted random sampling with updates - Citadel (medium)
  • Compute maximum later-earlier difference - Citadel (medium)