[Easy] 346. Moving Average from Data Stream
Given a stream of integers and a window size, calculate the moving average of all integers in the sliding window.
Implement the MovingAverage class:
MovingAverage(int size)Initializes the object with the size of the windowsize.double next(int val)Returns the moving average of the lastsizevalues of the stream.
Examples
Example 1:
Input
["MovingAverage", "next", "next", "next", "next"]
[[3], [1], [10], [3], [5]]
Output
[null, 1.0, 5.5, 4.66667, 6.0]
Explanation
MovingAverage movingAverage = new MovingAverage(3);
movingAverage.next(1); // return 1.0 = 1 / 1
movingAverage.next(10); // return 5.5 = (1 + 10) / 2
movingAverage.next(3); // return 4.66667 = (1 + 10 + 3) / 3
movingAverage.next(5); // return 6.0 = (10 + 3 + 5) / 3
Constraints
1 <= size <= 1000-10^5 <= val <= 10^5- At most
10^4calls will be made tonext.
Thinking Process
- Sliding window pattern: Queue naturally maintains FIFO order
- Maintain a window
[left, right]satisfying a constraint. - Expand
rightto grow; shrinkleftwhen invalid. - Fixed window: slide both pointers together.
Common Approaches
Typical techniques for this pattern:
| Approach | Time | Space | Notes |
|---|---|---|---|
| Fixed-size window (this problem) | O(n) | O(1) | Window size known upfront |
| Variable-size window | O(n) | O(1) | Expand/shrink until valid |
| Window + hash map | O(n) | O(k) | Track character/count frequencies |
| Deque window max | O(n) | O(k) | Monotonic deque for max/min in window |
Solution
Time Complexity: O(1) per next() call
Space Complexity: O(size) - Queue stores at most size elements
This solution uses a queue to maintain the sliding window and a running sum to calculate the average efficiently.
class MovingAverage:
deque[int> q
windowSize
long long windowSum
MovingAverage(size) :
windowSize = size
windowSum = 0
def next(self, val):
q.push(val)
windowSum += val
if len(q) > windowSize:
windowSum -= q[0]
q.pop()
return (double) windowSum / len(q)
/
Your MovingAverage object will be instantiated and called as such:
MovingAverage obj = new MovingAverage(size)
double param_1 = obj.next(val)
/
Solution Explanation
Approach: Fixed-size window (this problem)
Key idea: 1. Sliding window pattern: Queue naturally maintains FIFO order
How the code works:
- Sliding window pattern: Queue naturally maintains FIFO order
- Maintain a window
[left, right]satisfying a constraint. - Expand
rightto grow; shrinkleftwhen invalid. - Fixed window: slide both pointers together.
- Maintain a window
| Operation | Time | Space |
|---|---|---|
| Constructor | O(1) | O(1) |
| next() | O(1) | O(size) |
| Overall | O(1) per call | O(size) |
How Solution 1 Works
- Initialization:
- Store
windowSizeto know the maximum window size - Initialize
windowSumto 0
- Store
- Adding new value:
- Push new value to queue
- Add value to running sum
- Maintaining window size:
- If queue size exceeds
windowSize, remove oldest element - Subtract removed element from running sum
- If queue size exceeds
- Calculate average:
- Return
windowSum / q.size() - Note:
q.size()may be less thanwindowSizeinitially
- Return
Key Insight
- Running sum: Maintain sum of current window elements
- Queue: Automatically maintains FIFO order for sliding window
- O(1) average calculation: No need to sum all elements each time
Example Walkthrough
Input: size = 3, calls: next(1), next(10), next(3), next(5)
Solution 1 (Queue):
Initial: q = [], windowSum = 0
next(1):
q.push(1) → q = [1]
windowSum = 0 + 1 = 1
q.size() = 1
return 1.0 / 1 = 1.0
next(10):
q.push(10) → q = [1, 10]
windowSum = 1 + 10 = 11
q.size() = 2
return 11.0 / 2 = 5.5
next(3):
q.push(3) → q = [1, 10, 3]
windowSum = 11 + 3 = 14
q.size() = 3 (equals windowSize)
return 14.0 / 3 = 4.66667
next(5):
q.push(5) → q = [1, 10, 3, 5]
windowSum = 14 + 5 = 19
q.size() = 4 > windowSize
Remove q.front() = 1
windowSum = 19 - 1 = 18
q.pop() → q = [10, 3, 5]
return 18.0 / 3 = 6.0
Complexity
| Operation | Time | Space | |———–|——|——-| | Constructor | O(1) | O(1) | | next() | O(1) | O(size) | | Overall | O(1) per call | O(size) |
Common Mistakes
- Window not full: First few calls when
q.size() < windowSize - Single element window:
size = 1 - Large window size:
size = 1000 - Negative values:
val = -10^5 -
Many calls: Up to 10^4 calls
- Integer overflow: Using
intforwindowSuminstead oflong long - Division by zero: Not handling case when queue is empty (shouldn’t happen per constraints)
- Wrong average: Using
windowSizeinstead ofq.size()when window not full - Not removing old elements: Forgetting to pop when window is full
- Type conversion: Not casting to
doublebefore division
Optimization Tips
- Use
long long: Prevents overflow when summing many values - Queue vs Array: Queue is simpler, array is faster for fixed-size windows
- Early return: Can optimize for
size = 1case separately
Related Problems
- 239. Sliding Window Maximum - Find maximum in sliding window
- 480. Sliding Window Median - Find median in sliding window
- 643. Maximum Average Subarray I - Maximum average in fixed window
- 1423. Maximum Points You Can Obtain from Cards - Sliding window variant
Pattern Recognition
This problem demonstrates the “Sliding Window with Running Sum” pattern:
1. Use queue/array to maintain window
2. Maintain running sum of window elements
3. Add new element, update sum
4. Remove old element when window exceeds size
5. Calculate result from running sum
Similar problems:
- Sliding Window Maximum
- Sliding Window Median
- Maximum Average Subarray
- Subarray Sum Equals K
Real-World Applications
- Stock Price Analysis: Calculate moving average of stock prices
- Network Monitoring: Average network latency over time window
- Sensor Data: Smooth sensor readings over time
- Performance Metrics: Average response time in sliding window
- Signal Processing: Moving average filter for noise reduction
References
- LC 346: Moving Average from Data Stream on LeetCode
- LeetCode Discuss — LC 346: Moving Average from Data Stream
- LeetCode Editorial (may require premium)
Key Takeaways
- Sliding window pattern: Queue naturally maintains FIFO order
- Running sum optimization: Avoid recalculating sum each time
- Window size management: Check size before removing elements
- Type safety: Use
long longto prevent overflow with large sums