File: moving-average-from-data-stream/solution.py

Date: 2026-06-06

Time: 18:09

Purpose

This file solves LeetCode 346 — Moving Average from Data Stream. It implements a class that computes the moving average of the last size integers from a stream of values. It's a design problem — the core challenge is choosing the right data structure to make next() O(1).

Key Components

MovingAverage

A stateful stream processor. The constructor takes a window size; each call to next(val) ingests one integer and returns the average of the most recent size values (or fewer, if the stream hasn't produced that many yet).

_init(self, size: int) — Initializes a bounded deque (maxlen=size) and a running sum accumulator sum.

next(self, val: int) -> float — The only public method. Adds val to the stream, evicts the oldest value if the window is full, and returns the current average.

Patterns

Running sum with manual bookkeeping. Rather than calling sum(self.queue) on every next() call (which would be O(k) where k is the window size), the code maintains sum incrementally. When a value is about to be evicted (the deque is at capacity), it's subtracted from _sum before the new value is appended and added.

Bounded deque as a circular buffer. deque(maxlen=size) handles eviction automatically — append drops the leftmost element when full. But the code reads self.queue[0] *before* the append to subtract the evicted value from sum, since after the append the old head is gone.

Dependencies

Imports: collections.deque — the only dependency. No external packages.

Imported by: moving-average-from-data-stream/test_solution.py directly. The "Imported By" list in the prompt is misleadingly large — those are test files across the entire repo that share a common test harness, not files that import MovingAverage.

Flow

1. Caller creates MovingAverage(size=3).

2. Each next(val) call:

Example trace with size=3:

Invariants

Error Handling

None. The code trusts that size > 0 and val is numeric. Passing size=0 would cause a division-by-zero on the first next() call since deque(maxlen=0) silently drops every append, leaving len at 0. This matches LeetCode's constraints (1 <= size <= 1000).

Topics to Explore

Beliefs