Moving Average from Data Stream
Sliding window average — fixed-size deque holding the last k values, maintain a running sum.
2 min read
design sliding-window queue
Problem#
Implement a moving average over a stream: next(val) returns the average of the last up-to-size values seen.
Examples#
size=3; next(1)→1,next(10)→5.5,next(3)→4.667,next(5)→6.
Constraints#
1 <= size <= 1000, up to10^4calls.
Approach#
Fixed-capacity queue (deque). On next, push the new value and add to a running sum; if size exceeded, pop the front and subtract.
Solution#
class MovingAverage { deque<int> q; int sz; long long sum = 0;public: MovingAverage(int size) : sz(size) {} double next(int val) { q.push_back(val); sum += val; if ((int)q.size() > sz) { sum -= q.front(); q.pop_front(); } return (double)sum / q.size(); }};type MovingAverage struct { q []int sz int sum int}
func Constructor(size int) MovingAverage { return MovingAverage{sz: size}}
func (m *MovingAverage) Next(val int) float64 { m.q = append(m.q, val) m.sum += val if len(m.q) > m.sz { m.sum -= m.q[0] m.q = m.q[1:] } return float64(m.sum) / float64(len(m.q))}from collections import deque
class MovingAverage: def __init__(self, size: int): self.q: deque[int] = deque() self.sz = size self.total = 0
def next(self, val: int) -> float: self.q.append(val) self.total += val if len(self.q) > self.sz: self.total -= self.q.popleft() return self.total / len(self.q)class MovingAverage { constructor(size) { this.q = []; this.sz = size; this.sum = 0; }
next(val) { this.q.push(val); this.sum += val; if (this.q.length > this.sz) { this.sum -= this.q.shift(); } return this.sum / this.q.length; }}class MovingAverage { private Deque<Integer> q; private int sz; private long sum;
public MovingAverage(int size) { this.q = new ArrayDeque<>(); this.sz = size; this.sum = 0; }
public double next(int val) { q.offerLast(val); sum += val; if (q.size() > sz) { sum -= q.pollFirst(); } return (double) sum / q.size(); }}class MovingAverage { private q: number[] = []; private sz: number; private sum = 0;
constructor(size: number) { this.sz = size; }
next(val: number): number { this.q.push(val); this.sum += val; if (this.q.length > this.sz) { this.sum -= this.q.shift()!; } return this.sum / this.q.length; }}Editorial#
A running sum avoids re-summing the window each call. Once the deque hits capacity, every push pairs with a pop — strict sliding window in O(1).
Complexity#
- Time:
O(1)pernext. - Space:
O(size).
Concept revision#
Related#