Find deployable slots in a recurring week from allowed and freeze windows
StripeSoftware Engineer · OnsiteLast updated
A coding exercise on a recurring 10,080-minute week: combine allowed and freeze deployment windows into deployable slots, then add per-window time-zone offsets, the current time, a lead time, a minimum slot length and a cap of k results. It tests interval merging and subtraction, wrap-around at the week boundary and careful edge-case handling.
A deployment scheduler works on a recurring week of 10,080 minutes (7 days of 24 hours of 60 minutes). Minute 0 is the start of the week, and the same schedule repeats every week. Teams declare windows in which deployments are allowed and windows in which deployments are frozen. A minute is deployable when it lies inside at least one allowed window and inside no freeze window, and a deployable slot is a maximal run of consecutive deployable minutes.
The exercise came in two parts. Part 1 takes only (start, end, type) windows and returns every deployable slot of the week. Part 2 adds the current UTC time, a lead time, a minimum slot length, a cap k on the number of slots, and a time-zone offset for each window. Implement Part 2. Part 1 is the special case utc_now = 0, lead_time_minutes = 0, min_continuous_minutes = 1, every offset = 0, and k at least the number of slots.
Function Signature
def deployable_slots(utc_now: int, lead_time_minutes: int, min_continuous_minutes: int, k: int, windows: list[tuple[int, int, str, int]]) -> list[list[int]]:
Rules
- Each window is
(start, end, type, offset).startandendare minutes of the week in the window's local time, and the window covers the half-open range[start, end).typeis"allowed"or"freeze". offsetis the window's local time minus UTC, in minutes: a UTC-5 zone hasoffset = -300and a UTC+2 zone hasoffset = 120. In UTC the window covers[start - offset, end - offset).- All times are measured on one UTC timeline in minutes, where minute
0is the start of the current week and minute10080is the start of the next week. Every window occurs once per week on this timeline: at its UTC range, and at that range shifted by every multiple of 10,080 (forwards and backwards). A shifted window may therefore cross a week boundary. - Freeze wins: a minute inside any freeze occurrence is not deployable, even if an allowed occurrence also covers it. A minute covered by no allowed occurrence is not deployable.
utc_nowis the current UTC minute of the current week. The earliest usable minute isearliest = utc_now + lead_time_minutes. Because the schedule repeats weekly, only the search horizon[earliest, earliest + 10080)is considered.- A slot is a maximal run of deployable minutes inside the search horizon, reported as
[slot_start, slot_end]and meaning the half-open range[slot_start, slot_end). Runs are cut at both ends of the horizon. Deployable minutes that are consecutive on the timeline belong to one slot, even when they come from different windows or cross a week boundary. - Keep only slots with
slot_end - slot_start >= min_continuous_minutes, measured after cutting at the horizon. - Return the first
kkept slots in increasing order ofslot_start, fewer if fewer exist, and[]if there are none. Slots never overlap, so this order is unique.
Constraints
0 <= utc_now < 100800 <= lead_time_minutes <= 10^61 <= min_continuous_minutes <= 100801 <= k <= 10^40 <= len(windows) <= 10^40 <= start < end <= 10080for every window, in its local timetypeis exactly"allowed"or"freeze"-720 <= offset <= 840- Every returned value lies between
0andearliest + 10080, which is at most 1,020,159, so all values fit in a 32-bit signed integer.
Examples
Example 1
Input: utc_now = 0, lead_time_minutes = 0, min_continuous_minutes = 1, k = 10,
windows = [
(600, 1200, "allowed", 0),
(1000, 1080, "freeze", 0),
(1150, 1500, "allowed", 0),
(9900, 10080, "allowed", 0),
(0, 120, "allowed", 0)
]
Output: [[0, 120], [600, 1000], [1080, 1500], [9900, 10080]]
The freeze removes [1000, 1080) from the first allowed window. The overlapping allowed ranges [1080, 1200) and [1150, 1500) form one slot. The search horizon is [0, 10080), so [0, 120) and [9900, 10080) are reported as two slots even though the week wraps from one to the other.
Example 2
Input: utc_now = 10000, lead_time_minutes = 60, min_continuous_minutes = 90, k = 3,
windows = [
(0, 240, "allowed", 0),
(9960, 10080, "allowed", 0),
(120, 150, "freeze", 0),
(540, 720, "allowed", 120),
(3000, 3030, "allowed", 0)
]
Output: [[10060, 10200], [10230, 10320], [10500, 10680]]
earliest = 10060, so the horizon is [10060, 20140). The allowed run that starts at 9960 continues across the week boundary into next week's [10080, 10320). It is cut at 10060 and split by next week's freeze [10200, 10230), leaving slots of 140 and 90 minutes. The window with offset = 120 covers UTC [420, 600), which next week is [10500, 10680). Next week's [13080, 13110) lasts only 30 minutes and is dropped. A fourth qualifying slot, [20040, 20140), exists, but k = 3.
Example 3
Input: utc_now = 50, lead_time_minutes = 0, min_continuous_minutes = 30, k = 5,
windows = [
(0, 180, "allowed", 120),
(30, 60, "freeze", 120)
]
Output: [[9960, 9990], [10020, 10130]]
With offset = 120, the allowed window covers UTC [-120, 60), and its next weekly occurrence is [9960, 10140). The freeze covers [9990, 10020) in that occurrence. The horizon is [50, 10130). The run [50, 60) lasts 10 minutes and is dropped, [9960, 9990) lasts exactly 30 minutes and is kept, and [10020, 10140) is cut to [10020, 10130) at the end of the horizon.
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.