PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep

Quick Overview

This question evaluates understanding of interval scheduling and temporal resource allocation, testing algorithm design, complexity analysis, and appropriate data-structure use for assigning bookings to a minimal number of courts.

  • medium
  • Atlassian
  • Coding & Algorithms
  • Software Engineer

Assign tennis bookings to minimum courts

Company: Atlassian

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Onsite

## Expanding Tennis Club (Interval Scheduling) You run a tennis club with an unlimited number of courts. Each booking has a start and finish time. ```text class BookingRecord { int id; int startTime; int finishTime; } List<Assignment> assignCourts(List<BookingRecord> bookingRecords) ``` ### Part (a) Implement `assignCourts` to return a **plan that assigns each booking to a specific court** such that: - No court has overlapping bookings. - The total number of courts used is **minimized**. Your output can be any structure that includes, for each booking, the assigned `courtId`. ### Part (b) – maintenance buffer after each booking After each booking on a court, the court requires a fixed maintenance time `X` (e.g., cleaning) before it can be used again. - If a booking ends at time `t`, the next booking on the same court cannot start before `t + X`. Update the assignment logic accordingly. ### Part (c) – maintenance only after some usage Follow-up variant: maintenance is not required after every booking, but only after a court has accumulated a certain amount of usage (clarify with the interviewer whether this threshold is in number of bookings or total time used). Update the assignment approach to support this rule. ### Notes - Times are integers. - You may assume `startTime < finishTime`. - State any additional constraints you rely on (e.g., max N).

Quick Answer: This question evaluates understanding of interval scheduling and temporal resource allocation, testing algorithm design, complexity analysis, and appropriate data-structure use for assigning bookings to a minimal number of courts.

Expanding Tennis Club - Part (a): Minimum Courts

You run a tennis club with an unlimited number of courts. Each booking has an id, a start time, and a finish time. Two bookings overlap if their [start, finish) intervals intersect; a court may hold at most one booking at any instant (a booking ending exactly when another begins do NOT conflict). Given the list of bookings, assign every booking to a court so that no court ever has two overlapping bookings and the total number of distinct courts used is minimized. Return the assignment as a list of [id, courtId] pairs in the SAME order as the input bookings. Deterministic tie-breaking (so the output is unique): process bookings in order of (start, finish, id). When a booking begins, first release every court whose current finish time is <= the new booking's start. If any released/idle court is available, reuse the one with the SMALLEST courtId; otherwise open a new court numbered with the next integer starting from 0. Input: bookings is a list of [id, start, finish] with start < finish.

Constraints

  • 0 <= number of bookings
  • For each booking, start < finish; times are integers
  • Bookings touching at an endpoint (finish == next start) do not conflict
  • An unlimited number of courts is available; minimize the count actually used

Examples

Input: ([[1, 0, 30], [2, 5, 10], [3, 15, 20]],)

Expected Output: [[1, 0], [2, 1], [3, 1]]

Explanation: Booking 1 spans the whole window so it holds court 0. Booking 2 needs a second court (1). Booking 2 frees court 1 at time 10, so booking 3 (starts 15) reuses court 1. Two courts.

Input: ([[1, 1, 10], [2, 2, 7], [3, 3, 19], [4, 8, 12], [5, 10, 20], [6, 11, 30]],)

Expected Output: [[1, 0], [2, 1], [3, 2], [4, 1], [5, 0], [6, 3]]

Explanation: Peak overlap is 4 (around time 11, bookings 3,4,5,6 plus releases), so four courts (0..3) are used. Court 1 frees at 7 and is reused by booking 4; court 0 frees at 10 and is reused by booking 5.

Input: ([],)

Expected Output: []

Explanation: No bookings -> empty assignment.

Input: ([[7, 100, 200]],)

Expected Output: [[7, 0]]

Explanation: A single booking always takes court 0.

Input: ([[1, 0, 10], [2, 10, 20], [3, 20, 30]],)

Expected Output: [[1, 0], [2, 0], [3, 0]]

Explanation: Back-to-back bookings touch only at endpoints, so one court serves all three.

Input: ([[1, 0, 5], [2, 0, 5], [3, 0, 5]],)

Expected Output: [[1, 0], [2, 1], [3, 2]]

Explanation: Three fully simultaneous bookings force three separate courts.

Hints

  1. The minimum number of courts equals the maximum number of bookings overlapping at any single instant -- this is the classic 'minimum meeting rooms' result.
  2. Sort the events by start time; keep a min-heap of (finishTime, courtId) for courts in use so you can cheaply find the court that frees up earliest.
  3. To make the assignment deterministic, free every court whose finish <= the current start, then reuse the smallest available courtId, opening a new court only when none is free.

Expanding Tennis Club - Part (b): Maintenance Buffer After Each Booking

Same setup as Part (a): assign bookings to the minimum number of courts with no overlaps. NOW, after EVERY booking, a court needs a fixed maintenance time X (e.g. cleaning) before it can be rented again. If a booking on a court finishes at time t, the next booking on that SAME court cannot start before t + X. Given the bookings and the integer X, return the assignment as a list of [id, courtId] pairs in input order. Use the same deterministic greedy rule as Part (a), except a court that finishes at t becomes available again only at t + X. Process bookings in order of (start, finish, id); release a court only when (finish + X) <= the new booking's start; reuse the smallest available courtId, else open the next new court starting at 0. Input: bookings is a list of [id, start, finish]; x is a non-negative integer (X=0 reduces to Part (a)).

Constraints

  • 0 <= number of bookings
  • For each booking, start < finish; times are integers
  • x >= 0 (the maintenance buffer; x == 0 is equivalent to Part (a))
  • After a booking finishing at t, the next booking on that court must start at >= t + x

Examples

Input: ([[1, 0, 10], [2, 10, 20], [3, 20, 30]], 0)

Expected Output: [[1, 0], [2, 0], [3, 0]]

Explanation: With no buffer, back-to-back bookings share one court (same as Part (a)).

Input: ([[1, 0, 10], [2, 10, 20], [3, 20, 30]], 5)

Expected Output: [[1, 0], [2, 1], [3, 0]]

Explanation: Booking 1 finishes at 10 but court 0 is in maintenance until 15, so booking 2 (start 10) needs court 1. Court 0 is free again by time 20, so booking 3 reuses it.

Input: ([[1, 0, 10], [2, 15, 20], [3, 20, 30]], 5)

Expected Output: [[1, 0], [2, 0], [3, 1]]

Explanation: Court 0 frees at 10+5=15, exactly when booking 2 starts, so it is reused. Court 0 then frees at 20+5=25; booking 3 (start 20) cannot wait, so it takes court 1.

Input: ([], 3)

Expected Output: []

Explanation: No bookings -> empty assignment.

Input: ([[9, 0, 100]], 10)

Expected Output: [[9, 0]]

Explanation: A single booking takes court 0; the buffer is irrelevant with nothing after it.

Input: ([[1, 0, 5], [2, 0, 5]], 100)

Expected Output: [[1, 0], [2, 1]]

Explanation: Two simultaneous bookings always need two courts regardless of the buffer.

Input: ([[1, 0, 10], [2, 12, 20], [3, 12, 20]], 2)

Expected Output: [[1, 0], [2, 0], [3, 1]]

Explanation: Court 0 frees at 10+2=12, so booking 2 (start 12) reuses it; the simultaneous booking 3 must open court 1.

Hints

  1. The only change from Part (a) is when a court becomes reusable: treat its availability time as finish + X instead of finish.
  2. Push (finish + X, courtId) onto the in-use heap; a court is releasable for a new booking only when finish + X <= that booking's start.
  3. With X = 0 the algorithm must reproduce Part (a) exactly -- a good sanity check.

Expanding Tennis Club - Part (c): Maintenance Only After Accumulated Usage

Follow-up variant. Maintenance is no longer needed after EVERY booking. Instead each court accumulates usage, and the maintenance buffer X is paid only once a court's accumulated USED TIME (the sum of its bookings' durations) reaches a threshold T. After that maintenance fires, the court's accumulated-usage counter resets to 0. Concretely, when a booking with duration d = finish - start completes on a court: add d to that court's running usage. If the running usage is now >= T, the court enters maintenance and is unavailable until finish + X, then its usage counter resets to 0; otherwise the court is free again immediately at finish (no buffer). Given the bookings, the integer X (buffer), and the integer T (usage threshold), return the assignment as a list of [id, courtId] pairs in input order. Same deterministic greedy as before: process by (start, finish, id); reuse the smallest available courtId, else open the next new court from 0. This disambiguates the open-ended interview prompt by defining the threshold as TOTAL TIME USED (not number of bookings).

Constraints

  • 0 <= number of bookings
  • For each booking, start < finish; times are integers
  • x >= 0 (maintenance buffer), t >= 1 (usage-time threshold)
  • Threshold is interpreted as TOTAL accumulated used time on a court; the counter resets to 0 after each maintenance
  • A very large t means maintenance effectively never fires (reduces toward Part (a))

Examples

Input: ([[1, 0, 10], [2, 10, 20], [3, 20, 30]], 5, 1000)

Expected Output: [[1, 0], [2, 0], [3, 0]]

Explanation: Threshold 1000 is never reached, so no maintenance fires and one court serves all back-to-back bookings.

Input: ([[1, 0, 10], [2, 10, 20], [3, 20, 30]], 5, 10)

Expected Output: [[1, 0], [2, 1], [3, 0]]

Explanation: Booking 1 uses 10 >= T, so court 0 enters maintenance until 15; booking 2 (start 10) opens court 1 (also hits 10 >= T, maint until 25). Court 0 is free by 20, reused by booking 3.

Input: ([[1, 0, 6], [2, 6, 12], [3, 12, 18], [4, 18, 24]], 5, 10)

Expected Output: [[1, 0], [2, 0], [3, 1], [4, 0]]

Explanation: Court 0 usage after b1=6 (<10, free at 6) so b2 reuses it; after b2 usage=12 (>=10) -> maintenance until 17, counter resets. b3 (start 12) cannot use court 0, opens court 1. Court 0 frees at 17, so b4 (start 18) reuses court 0.

Input: ([], 5, 10)

Expected Output: []

Explanation: No bookings -> empty assignment.

Input: ([[9, 0, 100]], 10, 50)

Expected Output: [[9, 0]]

Explanation: A single booking takes court 0; its maintenance afterward never matters.

Input: ([[1, 0, 5], [2, 0, 5]], 100, 1)

Expected Output: [[1, 0], [2, 1]]

Explanation: Simultaneous bookings need two courts; with T=1 each immediately triggers maintenance, but that does not change the overlap requirement.

Input: ([[1, 0, 10], [2, 10, 20], [3, 22, 30], [4, 22, 30]], 5, 10)

Expected Output: [[1, 0], [2, 1], [3, 0], [4, 2]]

Explanation: b1 fills court 0 (usage 10 -> maint to 15, reset). b2 opens court 1 (maint to 25, reset). At time 22 court 0 is free so b3 reuses it (usage 8 < 10, free at 30); court 1 still in maintenance until 25, so simultaneous b4 opens court 2.

Hints

  1. Track per-court accumulated usage; only when it crosses T do you delay the court's next availability by X and reset the counter.
  2. Keep the same min-heap of (availableTime, courtId), but compute availableTime as finish + X when usage >= T, otherwise just finish.
  3. Edge behavior: with T larger than any possible accumulated usage the court is always free at finish (Part (a)); with T = 1 every nonzero-duration booking triggers maintenance (Part (b)).
Last updated: Jun 21, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,000+ 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

  • Compute a moving average on a stream - Atlassian (hard)
  • Find a secret word using match feedback - Atlassian (hard)
  • Implement sequential and parallel URL requests - Atlassian (medium)
  • Merge intervals and design rating APIs - Atlassian (medium)
  • Implement sliding-window rate limiter function - Atlassian (medium)