Practical coding
Hands-on coding for AI/ML engineering managers, built on team and delivery data: calendars and meeting rooms, on-call rotations, sprint capacity, project schedules and dependency cycles, org trees, delivery metrics, interview ranking, GPU budgets, roadmap picks, and small caches and rate limiters.
These problems are original practice. They are not questions from a named employer or a live hiring loop.
1.Free slots across calendars
Write
free_slots(calendars, day_start, day_end, min_length). Each calendar is one person's list of busy[start, end]meetings as"HH:MM"strings; meetings may extend past working hours. Return the gaps within[day_start, day_end]when nobody is busy and that last at leastmin_lengthminutes, as [["HH:MM", "HH:MM"], ...] sorted by start. Meetings ending at 10:00 and starting at 10:00 leave no gap.2.Minimum meeting rooms
Write
min_rooms(meetings). Each meeting is[start, end]in minutes from midnight with start < end. Return the minimum number of rooms so that no two meetings in the same room overlap. A meeting ending at 600 and one starting at 600 do not overlap and can share a room. Return 0 for no meetings.3.On-call rotation with swaps
Write
oncall_schedule(engineers, start_date, weeks, swaps). Week i (from 0) startsstart_date+ 7*i days ("YYYY-MM-DD") and goes toengineers[i % len(engineers)]. Each swap[date_a, date_b]exchanges the owners of those two weeks; apply swaps in order, skipping a swap if either date is not a week start in this schedule. Return [[week_start, engineer], ...] by date; [] if weeks is 0.4.Sprint capacity
Write
sprint_capacity(people, sprint_days, focus_factor). Each person is{"name", "days_off", "allocation"}where allocation is the share (0 to 1) of time on this team. A person's capacity ismax(0, sprint_days - days_off)* allocation *focus_factor. Return {"by_person":{name: capacity},"total": sum}, each value rounded to 1 decimal; total is the sum of the unrounded values, then rounded.5.Assign tickets by least load
Write
assign_tickets(loads, tickets). loads maps engineer to current load in points; tickets is a list of[ticket_id, points]handled in the given order. Each ticket goes to the engineer with the lowest current load (ties go to the alphabetically first name), whose load then grows by the ticket's points. Return{engineer: [ticket_ids in assignment order]}, including engineers who got none.6.Critical path length
Write
critical_path_length(durations, deps). durations maps task to its duration in days; each dep[a, b]means b cannot start until a finishes. Tasks without deps can start at day 0 and run in parallel. Return the minimum total project length, which is the largest finish time over all tasks. The graph has no cycles; return 0 if there are no tasks.7.Earliest start date per task
Write
earliest_start_dates(durations, deps, project_start). durations maps task to days (calendar days, weekends count); dep[a, b]means b starts after a finishes. A task starting on day s with duration d lets successors start on day s + d. Tasks with no prerequisites start onproject_start("YYYY-MM-DD"). Return{task: earliest start as "YYYY-MM-DD"}for every task. No cycles.8.Report a dependency cycle
Write
find_cycle(deps). Each dep[a, b]means a must finish before b. The input has at most one cycle. Return it as a list of tasks in dependency order, starting at the alphabetically smallest task in the cycle and ending with that task again, e.g.["a", "c", "b", "a"]. A task depending on itself gives["x", "x"]. Return [] if there is no cycle.9.Headcount roll-up
Write
headcount(org). org is a list of[employee, manager]pairs; the manager isNonefor a root, and every manager also appears as an employee. Return{employee: number of people below them}, counting direct and indirect reports, for every employee. People with no reports map to 0. Return {} for an empty org.10.Chain of command
Write
chain_of_command(managers, employee). managers maps each employee to their manager, or toNonefor the root. Return the list of names from employee up to and including the root, e.g.["eng", "lead", "ceo"]. If employee is the root, return[employee]. If employee is not in managers, return [].11.Span of control outliers
Write
span_outliers(org, low, high). org is a list of[employee, manager]pairs (managerNonefor the root). A manager is anyone with at least one direct report. Return [[manager, direct report count], ...] for managers whose count is below low or above high, sorted by name. Counts equal to low or high are fine. People with no reports are never listed.12.Median PR review latency
Write
review_latency(reviews). Each review is{"reviewer", "requested", "reviewed"}with times as"YYYY-MM-DD HH:MM"; reviewed isNoneif still pending. Latency is reviewed minus requested in hours. Return{reviewer: median latency rounded to 2 decimals}, ignoring pending reviews; with an even count, the median is the mean of the two middle values. Omit reviewers with no finished review.13.Deploy frequency and failure rate
Write
deploy_metrics(deploys, start, end). deploys is a list of{"date": "YYYY-MM-DD", "failed": bool}; count only those with start <= date <= end.per_day= count / days in the window (both ends included).failure_rate= failed / count, or 0.0 if count is 0. Return{"deploys": count, "per_day": per_day, "failure_rate": failure_rate}, floats rounded to 3 decimals.14.Mean time to restore
Write
mean_time_to_restore(incidents, severities). Each incident is{"severity", "start", "restored"}with times as"YYYY-MM-DD HH:MM"; restored isNonewhile still open. Using only restored incidents whose severity is in severities, return the mean of (restored - start) in minutes, rounded to 1 decimal. ReturnNoneif no incident qualifies.15.Rank candidates by weighted score
Write
rank_candidates(scores, weights). scores maps candidate to{round: score}; weights maps round to weight. A candidate's score issum(weight * score)/sum(weights)over rounds in weights, a missing round scoring 0, rounded to 2 decimals. Return [[rank, name, score], ...] sorted by score descending, then name. Equal rounded scores share a rank and the next rank skips (1, 1, 3).16.Greedy interview scheduling
Write
schedule_interviews(candidates, slots). slots: list of[interviewer, start](minutes). candidates: list of[name, earliest, latest]. In input order, each candidate takes the open slot with the earliest start where earliest <= start <= latest (ties: alphabetically first interviewer); a taken slot is gone. Return{name: [interviewer, start]}for every candidate (Noneif no slot fits).17.Group experiments by owner and status
Write
group_experiments(experiments). Each experiment is{"id", "owner", "status"}. Status text is messy: normalize it by trimming leading and trailing whitespace and lowercasing, so" Running"and"running"match. Return {owner:{status: [ids sorted as plain strings, so "exp-10" < "exp-2"]}}, including only statuses that occur for that owner. Return {} for no experiments.18.GPU hours with a cap
Write
allocate_gpu_hours(requests, total, cap). requests maps team to hours asked; a team's limit ismin(request, cap). First each team getsfloor(total * request / sum of requests), cut to its limit. Then give out leftover hours one by one, cycling through teams in name order and skipping teams at their limit, until none remain or all are capped. Return{team: hours}; all 0 if requests sum to 0.19.Pick roadmap projects
Write
pick_projects(projects, capacity). Each project is[name, cost, value]with cost >= 1 (engineer-weeks); there are at most 15. Choose a set with total cost <= capacity that maximizes total value. Among sets with equal value, pick the lowest total cost, then the alphabetically smallest sorted name list. Return{"projects": sorted names, "value": total value}.20.Reconcile two stack ranks
Write
reconcile_ranks(list_a, list_b). Two managers each ranked people best first; names may appear in one or both lists. A name's position is 1-based; if missing from a list, its position there is that list's length + 1. Order everyone by the sum of both positions, ascending; break ties by the better (smaller) of the two positions, then by name. Return the list of names.21.Longest on-time streak
Write
longest_on_time_streak(deliveries). Each delivery is{"due": "YYYY-MM-DD", "delivered": "YYYY-MM-DD" or None}. It is on time if delivered is notNoneand delivered <= due. Order deliveries by due date (equal due dates keep input order) and return the length of the longest run of consecutive on-time deliveries. Return 0 for no deliveries.22.Completion date from velocity
Write
estimate_completion(remaining, velocities, start_date, sprint_length). velocities are past sprint points, oldest first; velocity is the mean of the last 3 (or all, if fewer). sprints =ceil(remaining / velocity), so 0 when remaining is 0. Return {"sprints": sprints,"date":start_date+ sprints *sprint_lengthdays as"YYYY-MM-DD"}, orNoneif there is no history or velocity is 0.23.Rate-limit a notification bot
Write
rate_limit(messages, limit, window). messages is a list of[time_seconds, channel], sorted by time. A message is sent if its channel has sent fewer than limit messages at times t' with t - window < t' <= t (a send exactly window seconds earlier no longer counts). Dropped messages do not count. Return a list of booleans, one per message,Trueif sent.24.LRU cache for dashboard queries
Write
lru_cache(capacity, operations). Each operation is["put", query, result]or["get", query]. A get returns the cached result (orNone) and marks the query most recently used. A put stores or updates the query, marks it most recently used, and if the cache then holds more than capacity entries, evicts the least recently used. Return the get results in order. Capacity 0 stores nothing.25.Top K risks
Write
top_risks(risks, k). Each risk is{"name", "likelihood", "impact"}with integers 1 to 5; its score is likelihood * impact. Return the top k as [[name, score], ...] ordered by score descending, then higher impact first, then name ascending. If k exceeds the number of risks, return all of them; k = 0 returns [].26.Pages per on-call engineer
Write
pages_per_engineer(shifts, pages). shifts is a list of[engineer, start, end]covering start <= t < end (minutes; shifts never overlap; one engineer may have several). pages is a list of page times. Count pages per engineer by the shift they fall in. Return{engineer: count}for every engineer in shifts (0 if none) plus key"unassigned"for pages outside every shift (always present).27.Meeting minutes per person
Write
meeting_minutes(meetings). Each meeting is{"attendees": [names], "start": minutes, "end": minutes}. For each person, return the total minutes they are in at least one meeting; overlapping meetings count once (10:00-11:00 and 10:30-11:30 is 90 minutes). Return{person: minutes}for everyone who attends any meeting; {} if there are none.28.Hiring funnel conversion
Write
funnel_conversion(stages, candidates). stages lists funnel stages in order; candidates maps name to the furthest stage reached, and reaching a stage means passing all earlier ones. Return [[stage, count reaching it, rate], ...] in stage order, where rate is count / previous stage's count rounded to 3 decimals. The first stage's rate is always 1.0; a rate is 0.0 when the previous count is 0.29.Time-off coverage gaps
Write
coverage_gaps(team, time_off, start, end, min_staff). team is a list of names;time_offis a list of[name, first_day, last_day](inclusive"YYYY-MM-DD"; one person's ranges may overlap). For each weekday (Monday to Friday) from start to end inclusive, present = team size minus distinct people off. Return [[date, present], ...] in date order for days where present <min_staff.