When the Hours Touch
A medium Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.
- Domain
- Python
- Difficulty
- medium
- Seniority
- mid
- Asked in
- Lyft
Problem
Online stretches in this status export arrive unsorted, and a flaky app reconnecting mid-session leaves many of them overlapping or meeting exactly end-to-end, each a [start, end] pair of timestamps in seconds with sub-second fractions. Collapse a driver's sessions into the distinct windows of time the driver was actually online, earliest window first.
Two sessions that overlap are really one. Find the windows a driver was actually online.
Example 1
Input:
sessions = [[10,30.5],[4.5,12],[40,50.25],[33,42]]
Output:
[[4.5,30.5],[33,50.25]]
Example 2
Input:
sessions = [[0,15],[15,20],[30,35]]
Output:
[[0,20],[30,35]]
Worked solution and explanation
Why this problem exists in real interviews
This is interval coalescing wearing a session-cleanup costume. The skill being probed is whether you know the merge only works AFTER you sort by start time. The data hands you sessions in arrival order, and two overlapping stretches are almost never next to each other, so the candidate who walks the raw list comparing each session to the previous one quietly reports overlapping windows as separate. And because the timestamps are continuous, you cannot dodge the merge by dumping every covered instant into a set and regrouping contiguous points; there is no finite grid to enumerate. Sort by start first and every mergeable pair becomes adjacent; that single invariant is the whole problem.
Break down the requirements
Step 1: Sort by start time to make overlaps adjacent
Sort the sessions so they run in start order. Two-element lists already compare on their first element, which is the start, so a plain sorted(sessions) does it and no custom key is needed. When two sessions share a start, the one with the smaller end comes first, and the merge takes the larger end either way. Once sorted, any session that overlaps an earlier one must overlap the window you are building, because nothing with an earlier start is still ahead of you. A single pass over the unsorted input never establishes this.
Step 2: Sweep, extending a running window
Seed the result with the first session. For each later session, if its start is less than or equal to the current window's end, it overlaps or touches, so extend the window's end to the max of the two ends. Otherwise it starts a fresh window. The 'less than or equal' is what makes back-to-back sessions like [0.0, 15.0] and [15.0, 20.0] collapse into [0.0, 20.0].
Step 3: Take the max of the ends, not the latest end
When a session sits fully inside the current window, its end is smaller, so assigning the new end would shrink the window and lose coverage. Always extend with max(last[1], end). This is the line that handles [1.0, 100.0] swallowing [20.0, 30.0].
The solution
def merge_sessions(sessions):
if not sessions:
return []
ordered = sorted(sessions)
merged = [list(ordered[0])]
for start, end in ordered[1:]:
last = merged[-1]
if start <= last[1]:
last[1] = max(last[1], end)
else:
merged.append([start, end])
return merged- Single pass, no sort
- Walk the list in arrival order and compare each session to the previous one. On [[10.0, 30.5], [4.5, 12.0], ...] the [4.5, 12.0] arrives after [10.0, 30.5], so a forward-only scan either emits it as a separate window or extends in the wrong direction and loses the 4.5 start. Wrong answer, and it looks right on already-sorted inputs, which is how it slips through.
- Sort then sweep
- Sorting guarantees that if a session overlaps anything earlier, it overlaps the window currently being built. One comparison against the last window suffices, and every overlap is caught.
Common follow-up questions
- Now the export interleaves sessions for thousands of drivers in one list. How do you coalesce per driver? (Tests grouping by `driver_id` first (a `defaultdict` of lists) then coalescing each group, versus trying to sweep the mixed stream.)
- Instead of the windows, return the total time in seconds each driver was online. (Tests summing `end - start` over the coalesced windows and recognizing you must coalesce first to avoid double-counting overlap.)
- Sessions arrive as an unbounded stream rather than a finite list. What changes? (Tests reasoning about ordering guarantees, buffering late events, and emitting a window only once it can no longer be extended.)