The Narrow Lens
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
- L5
- Asked in
- Sigmoid
Problem
Raw sensor values arrive in order and are smoothed before alerting by replacing each reading with the average of that reading and the ones just before it, at most window_size readings in all. A window_size below 1 means smoothing is switched off for the stream, and the result is an empty list.
A narrow timeframe. Everything inside matters.
Example 1
Input:
window_size = 3, values = [10,20,30,40,50]
Output:
[10,15,20,30,40]
Example 2
Input:
window_size = 2, values = [5,15,25]
Output:
[5,10,20]
Worked solution and explanation
Why this problem exists in real interviews
This is a trailing-average smoother wearing a sensor-stream costume, and the whole problem lives in one decision: what do you divide by? Everyone gets the full-window region right. What separates candidates is the warm-up region, the positions before the window has filled, where the correct divisor is how many readings you actually have, not the window size you were handed. Get that wrong and every early output comes back deflated, which on a real alerting pipeline means the first few minutes of every stream silently read low.
Break down the requirements
Step 1: Read the contract: stateless function, parallel output
The signature is the_narrow_lens(window_size, values) and it returns a list the same length as values. There is no class and no state carried across calls. One list in, one fully materialized list out, one trailing average per input position.
Step 2: Handle the warm-up region
At index i the divisor is the count of readings actually in the window, which is min(i + 1, window_size), not window_size. The positions before the window fills are warm-up and average every reading seen so far. Dividing by the full window size early returns deflated averages and fails the first visible test at index 0.
Step 3: Branch on warm-up versus full window
Split the positions in two. While i < window_size the window is the warm-up prefix values[:i + 1]; after that it is values[i - window_size + 1:i + 1], inclusive of position i and exactly window_size long. Branching this way also means the start index can never go negative, so Python's wrap-around slicing never pulls readings from the end of the list. Slicing to i instead of i + 1 shifts every average back one slot.
Step 4: Guard the window that holds nothing
A window_size below 1 means smoothing is off, and the statement asks for an empty list. Without the guard, a zero-size window slices out nothing and sum(window) / len(window) divides by zero. One early if window_size < 1 or not values: return [] settles it before the main path starts.
The solution
def the_narrow_lens(window_size, values):
# A window that holds no readings has no average to report.
if window_size < 1 or not values:
return []
averages = []
for i in range(len(values)):
if i < window_size:
# Warm-up: the window is everything seen so far.
window = values[:i + 1]
else:
window = values[i - window_size + 1:i + 1]
averages.append(sum(window) / len(window))
return averagesCommon follow-up questions
- Rewrite this so each output element costs O(1) instead of O(`window_size`). What invariant do you maintain across iterations? (Tests the running-sum optimization. Maintain `running = running + values[i] - values[i - window_size]` once `i >= window_size`. Each step is O(1), and the full pass becomes O(n).)
- How does the algorithm change if the harness asked for the moving median instead of the moving average? (Tests the two-heap or sorted-container pattern. A median needs O(log w) per step using a max-heap of the lower half and a min-heap of the upper half, with rebalancing on each slide.)
- If `values` were 10M floats from a sensor stream, what breaks first and how do you defend against it? (Tests numerical stability. With long streams of large floats, the running sum drifts due to floating-point error. Periodic full recomputation, Kahan summation, or chunked partial sums all bound the drift.)