# Steady State

> Turn a jittery stream into a calm read, one step at a time.

Canonical URL: <https://datadriven.io/problems/steady_state>

Domain: Python · Difficulty: medium · Seniority: L4

## Problem

A monitoring service buffers raw metric samples in `nums`, and the dashboard smooths the jitter by reporting the mean of each run of `k` consecutive samples, each value rounded to two decimals. Return one average per window, in sample order. When there are fewer than `k` samples there is nothing to smooth, so return an empty list.

## Worked solution and explanation

### What this really is

Strip the time-series costume and this is a running-sum problem. The skill being probed is whether you can compute every window's mean in one pass instead of re-summing `k` numbers per window. Anyone can nest two loops; the tell is whether you carry a running sum and only adjust it by the one element that leaves and the one that enters. Miss that and a long stream with a wide window turns an O(n) task into O(n * k).

### The trap most people walk into

The prompt says return an empty list when there are fewer than `k` samples, and that clause is load-bearing. If you jump straight into summing the first `k` elements without checking the length first, a short input indexes past the end of the list and throws instead of returning []. Guard the length before you touch nums[k-1].

#### Step 1: Handle the short-input case first

If `len(nums) < k`, return [] immediately. This both satisfies the spec and protects the first-window sum from an index error.

#### Step 2: Seed the running sum

Sum the first `k` elements once. This is the only full summation you ever do.

#### Step 3: Slide one element at a time

For each later position, add the entering element and subtract the one that fell out of the window, then store the rounded mean. The sum updates in O(1).

---

### The solution

**Running sum, one pass**

```python
def moving_average(nums, k):
    if len(nums) < k:
        return []
    result = []
    window_sum = sum(nums[:k])
    result.append(round(window_sum / k, 2))
    for i in range(k, len(nums)):
        window_sum += nums[i] - nums[i - k]
        result.append(round(window_sum / k, 2))
    return result
```

*Seed once, then adjust by the entering and leaving element per step.*

> **Why this stays cheap**
>
> **Time:** O(n), a single pass after the seed sum. **Space:** O(n - k + 1) for the output. The naive re-sum-per-window version is O(n * k); on a 1M-sample stream with a 1000-wide window that is the difference between a million and a billion adds.

> **Interviewers watch for**
>
> The dead giveaway of a junior answer is recomputing sum(nums[i:i+k]) inside the loop. A senior carries the sum and mutates it by exactly two elements per step, and mentions the length guard before being asked.

> **Common pitfall**
>
> Repeated add-then-subtract on floats lets tiny rounding error accumulate in the running sum over a very long stream. For dashboards it is harmless, but naming it (and noting you could periodically re-seed the sum) signals you have shipped this for real.

---

## Common follow-up questions

- What if the dashboard wanted the moving median instead of the mean? _(Tests a sorted container or two-heap approach for O(k log k) per window.)_
- How would you compute this on a never-ending streaming input? _(Tests a fixed-size deque buffer instead of random access into a list.)_
- Does anything change if samples can be negative or non-integer? _(Tests handling negative or fractional samples and confirming the rounding still holds.)_

## Related

- [All practice problems](https://datadriven.io/problems)
- [Mock interview mode](https://datadriven.io/interview/steady_state)
- [Python Interview Questions](https://datadriven.io/python-interview-questions)
- [Data Engineering Interview Prep Guide](https://datadriven.io/data-engineer-interview-prep)
- [Daily Challenge](https://datadriven.io/daily)

---

Source: DataDriven (https://datadriven.io). DataDriven is the data engineering interview community. Live code execution in SQL, Python, and Spark sandboxes. Every feature is open to every member.