This problem requires implementing a MovingAverage
class that calculates the moving average of a stream of integers within a given window size. Two approaches are presented: one using an array and another using a queue.
This approach utilizes a circular array to store the last size
numbers in the stream. We maintain a running sum (s
) and a counter (cnt
) to track the number of elements processed.
Algorithm:
Initialization: The constructor initializes the array (arr
), sum (s
), and counter (cnt
).
next(val)
:
idx
) in the circular array to store the new value.val
) and subtracting the old value at the same index (to maintain a running sum of the window).Time Complexity: O(1) for next
operation. All operations within next
are constant time.
Space Complexity: O(size) to store the array.
This approach leverages a queue (FIFO) data structure to maintain the sliding window.
Algorithm:
Initialization: The constructor initializes the queue (q
), sum (s
), and window size (n
).
next(val)
:
n
). If full, removes the oldest element from the front of the queue and updates the sum accordingly.Time Complexity: O(1) for next
operation (amortized). Enqueue and dequeue operations are constant time.
Space Complexity: O(size) to store the queue.
The code examples in Python, Java, C++, and Go are provided above, and each one follows the same basic algorithm as described above for the chosen approach (array or queue). The comments in the code explain specific steps. Note that the queue-based approach might be slightly more efficient in some languages because queue operations are optimized.
Choosing between the array and queue approaches is largely a matter of preference and language-specific efficiencies. Both offer the same time and space complexity for this problem. If you are working in a language where queues are particularly efficient, the queue approach might be slightly favored. If you prefer a simpler, more direct approach, the array approach might be more appealing.